<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha256-Z1K5uhUaJXA7Ll0XrZ/0JhX4lAtZFpT6jkKrEDT0drU=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"example.com","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.14.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":-1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta property="og:type" content="website">
<meta property="og:title" content="JsyBlog">
<meta property="og:url" content="http://example.com/page/23/index.html">
<meta property="og:site_name" content="JsyBlog">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="SongyangJi">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://example.com/page/23/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"page/23/index.html","title":""}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>JsyBlog</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">JsyBlog</h1>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-overview-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">SongyangJi</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">251</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">45</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">109</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner index posts-expand">

    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/28/SpringBoot%E9%9B%86%E6%88%90Redis-%E2%80%94%E2%80%94%E2%80%94%E2%80%94-%E5%BA%8F%E5%88%97%E5%8C%96%E9%85%8D%E7%BD%AE%E3%80%81%E5%B8%B8%E8%A7%81%E5%B7%A5%E5%85%B7%E7%B1%BB%E3%80%81%E5%9F%BA%E6%9C%AC%E7%9A%84CRUD/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/28/SpringBoot%E9%9B%86%E6%88%90Redis-%E2%80%94%E2%80%94%E2%80%94%E2%80%94-%E5%BA%8F%E5%88%97%E5%8C%96%E9%85%8D%E7%BD%AE%E3%80%81%E5%B8%B8%E8%A7%81%E5%B7%A5%E5%85%B7%E7%B1%BB%E3%80%81%E5%9F%BA%E6%9C%AC%E7%9A%84CRUD/" class="post-title-link" itemprop="url">SpringBoot集成Redis ———— 序列化配置、常见工具类、基本的CRUD</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-28 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-28T00:00:00+08:00">2021-09-28</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-10-24 14:26:47" itemprop="dateModified" datetime="2021-10-24T14:26:47+08:00">2021-10-24</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Redis/" itemprop="url" rel="index"><span itemprop="name">Redis</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h2 id="Maven依赖"><a href="#Maven依赖" class="headerlink" title="Maven依赖"></a>Maven依赖</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-data-redis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- lettuce连接池需要依赖下面的jar包 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.commons<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>commons-pool2<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p>序列化依赖，如果使用 spring-boot-starter-web, 就不需要了。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-json<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>



<h2 id="Java-连接-redis-的客户端"><a href="#Java-连接-redis-的客户端" class="headerlink" title="Java 连接 redis 的客户端"></a>Java 连接 redis 的客户端</h2><blockquote>
<p>操作redis的客户端有jedis跟Lettuce。在springboot1.x系列中，其中使用的是jedis,但是到了springboot2.x其中使用的是Lettuce。 因为我们的版本是springboot2.x系列，所以今天使用的是Lettuce。<br>关于jedis跟lettuce的区别：</p>
<ul>
<li>Lettuce 和 Jedis 的定位都是Redis的client，所以他们当然可以直接连接redis server  </li>
<li>Jedis在实现上是直接连接的redis server，如果在多线程环境下是非线程安全的，这个时候只有使用连接池，为每个Jedis实例增加物理连接;</li>
<li>Lettuce的连接是基于Netty的，连接实例（StatefulRedisConnection）可以在多个线程间并发访问，应为StatefulRedisConnection是线程安全的，所以一个连接实例（StatefulRedisConnection）就可以满足多线程环境下的并发访问，当然这个也是可伸缩的设计，一个连接实例不够的情况也可以按需增加连接实例。</li>
</ul>
</blockquote>
<h2 id="序列化配置"><a href="#序列化配置" class="headerlink" title="序列化配置"></a>序列化配置</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory connectionFactory)</span> &#123;</span><br><span class="line">        <span class="type">RedisTemplate</span> <span class="variable">redisTemplate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>();</span><br><span class="line">        <span class="comment">// 设置template获得 redis-connection 的工厂</span></span><br><span class="line">        redisTemplate.setConnectionFactory(connectionFactory);</span><br><span class="line">        <span class="comment">// 设置序列化器</span></span><br><span class="line">        redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);</span><br><span class="line">        redisTemplate.setValueSerializer(RedisSerializer.json()); <span class="comment">// value 序列化器使用 Json</span></span><br><span class="line">        redisTemplate.setHashKeySerializer(StringRedisSerializer.UTF_8);</span><br><span class="line">        redisTemplate.setHashValueSerializer(StringRedisSerializer.UTF_8);</span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="yml基本配置"><a href="#yml基本配置" class="headerlink" title="yml基本配置"></a>yml基本配置</h2><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">database:</span> <span class="number">0</span> <span class="comment">#使用第几个数据库</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">localhost</span> <span class="comment">#redis服务器地址</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">6379</span> <span class="comment">#端口号</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">~</span> <span class="comment">#redis服务器连接密码</span></span><br><span class="line">    <span class="attr">timeout:</span> <span class="number">10000</span>  <span class="comment"># 连接超时时间（单位：毫秒）</span></span><br><span class="line">    <span class="attr">lettuce:</span></span><br><span class="line">      <span class="attr">pool:</span></span><br><span class="line">        <span class="comment">## 下面的值其实是lettuce连接池的默认配置，有兴趣的可以点进源码看一下</span></span><br><span class="line">        <span class="attr">max-active:</span> <span class="number">8</span> <span class="comment">#连接池最大连接数（使用负值表示没有限制）</span></span><br><span class="line">        <span class="attr">max-wait:</span> <span class="number">-1</span>  <span class="comment">#连接池最大阻塞等待时间（单位：使用负值表示没有限制）</span></span><br><span class="line">        <span class="attr">max-idle:</span> <span class="number">8</span> <span class="comment">#连接池中的最大空闲连接</span></span><br><span class="line">        <span class="attr">min-idle:</span> <span class="number">0</span> <span class="comment">#连接池中的最小空闲连接</span></span><br></pre></td></tr></table></figure>



<h2 id="工具类"><a href="#工具类" class="headerlink" title="工具类"></a>工具类</h2><h3 id="Json工具类"><a href="#Json工具类" class="headerlink" title="Json工具类"></a>Json工具类</h3><p>主要是将检查型异常改为运行时异常抛出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Json工具类, 功能为对象和字符串互相转换</span></span><br><span class="line"><span class="comment"> * 注意，jackson的属性注入是 无参构造器+getter+setter</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">JsonUtil</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">ObjectMapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Serialize any Java value as a String.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">stringfy</span><span class="params">(Object object)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> mapper.writeValueAsString(object);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (JsonProcessingException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;JsonUtil stringfy error: &quot;</span> + e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Deserialize JSON content from given JSON content String.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T <span class="title function_">parse</span><span class="params">(String content, Class&lt;T&gt; valueType)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> mapper.readValue(content, valueType);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (JsonProcessingException e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;JsonUtil parse error: &quot;</span> + e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="简单Bean类与Map之间的转换"><a href="#简单Bean类与Map之间的转换" class="headerlink" title="简单Bean类与Map之间的转换"></a>简单Bean类与Map之间的转换</h3><p>这个工具类的转换，主要是在使用 redis 的 hash 结构去存储实体类的时候使用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: SongyangJi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span>: 提供简单bean类与map之间的转化</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span>: 2021/9/16</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BeanAndMapConvertUtil</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Map&lt;String, Object&gt; <span class="title function_">beanToMap</span><span class="params">(Object object)</span> &#123;</span><br><span class="line">        Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;String, Object&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Field field : object.getClass().getDeclaredFields()) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="type">boolean</span> <span class="variable">flag</span> <span class="operator">=</span> field.isAccessible();</span><br><span class="line">                field.setAccessible(<span class="literal">true</span>);</span><br><span class="line">                <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> field.get(object);</span><br><span class="line">                map.put(field.getName(), obj != <span class="literal">null</span> ? obj.toString() : <span class="string">&quot;&quot;</span>);</span><br><span class="line">                field.setAccessible(flag);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e.getMessage());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> map;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T <span class="title function_">mapToBean</span><span class="params">(Map&lt;String, Object&gt; map, Class&lt;T&gt; beanClass)</span> &#123;</span><br><span class="line">        T t;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            t = beanClass.newInstance();</span><br><span class="line">            <span class="keyword">for</span> (Field field : beanClass.getDeclaredFields()) &#123;</span><br><span class="line">                <span class="keyword">if</span> (map.containsKey(field.getName())) &#123;</span><br><span class="line">                    <span class="type">boolean</span> <span class="variable">flag</span> <span class="operator">=</span> field.isAccessible();</span><br><span class="line">                    field.setAccessible(<span class="literal">true</span>);</span><br><span class="line">                    <span class="type">Object</span> <span class="variable">obj</span> <span class="operator">=</span> map.get(field.getName());</span><br><span class="line">                    <span class="keyword">if</span> (obj != <span class="literal">null</span>) &#123;</span><br><span class="line">                        <span class="keyword">if</span> (field.getType().isAssignableFrom(obj.getClass())) &#123;</span><br><span class="line">                            field.set(t, obj);</span><br><span class="line">                        &#125;</span><br><span class="line">                        field.setAccessible(flag);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(e.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> t;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>





<h2 id="CRUD"><a href="#CRUD" class="headerlink" title="CRUD"></a>CRUD</h2><h3 id="简单的Entity"><a href="#简单的Entity" class="headerlink" title="简单的Entity"></a>简单的Entity</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">long</span> userId;</span><br><span class="line"></span><br><span class="line">    String name;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="type">double</span> weight;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> score;</span><br><span class="line"></span><br><span class="line">    LocalDate lastSignDay;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="测试-String"><a href="#测试-String" class="headerlink" title="测试 String"></a>测试 String</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">testString</span><span class="params">()</span> &#123;</span><br><span class="line">      redisTemplate.opsForValue().set(<span class="string">&quot;str_key&quot;</span>, <span class="string">&quot;hello_world&quot;</span>);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>





<h3 id="测试-Hash"><a href="#测试-Hash" class="headerlink" title="测试 Hash"></a>测试 Hash</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">testBeanAndHash</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="type">User</span> <span class="variable">songyangJi</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">12345L</span>, <span class="string">&quot;SongyangJi&quot;</span>, <span class="number">18</span>, <span class="number">73.5</span>, <span class="number">0</span>, <span class="literal">null</span>);</span><br><span class="line">      <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_hash_key</span> <span class="operator">=</span> <span class="string">&quot;user_hash&quot;</span>;</span><br><span class="line"></span><br><span class="line">      System.out.println(<span class="string">&quot;------ 使用 Hash 存储对象 ------&quot;</span>);</span><br><span class="line">      <span class="comment">// 使用Hash结构，map传入</span></span><br><span class="line">      redisTemplate.opsForHash().putAll(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), BeanAndMapConvertUtil.beanToMap(songyangJi));</span><br><span class="line"></span><br><span class="line">      <span class="type">BoundHashOperations</span> <span class="variable">hashOs</span> <span class="operator">=</span> redisTemplate.boundHashOps(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId());</span><br><span class="line">      System.out.println(hashOs.get(<span class="string">&quot;userId&quot;</span>));</span><br><span class="line">      System.out.println(hashOs.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">      hashOs.put(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;gong chen bo&quot;</span>);</span><br><span class="line">      hashOs.increment(<span class="string">&quot;age&quot;</span>, <span class="number">1</span>);</span><br><span class="line">      System.out.println(hashOs.keys());</span><br><span class="line">      System.out.println(hashOs.values());</span><br><span class="line">      System.out.println(hashOs.entries());</span><br><span class="line">&#125;     </span><br></pre></td></tr></table></figure>



<h3 id="测试-Json序列化"><a href="#测试-Json序列化" class="headerlink" title="测试 Json序列化"></a>测试 Json序列化</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">testBeanAndHash</span><span class="params">()</span> &#123;</span><br><span class="line">     <span class="type">User</span> <span class="variable">songyangJi</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">12345L</span>, <span class="string">&quot;SongyangJi&quot;</span>, <span class="number">18</span>, <span class="number">73.5</span>, <span class="number">0</span>, <span class="literal">null</span>);</span><br><span class="line">     <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_json_key</span> <span class="operator">=</span> <span class="string">&quot;user_json&quot;</span>;</span><br><span class="line"></span><br><span class="line">     System.out.println(<span class="string">&quot;------- 使用 Json 存储对象 -------&quot;</span>);</span><br><span class="line">     redisTemplate.opsForValue().set(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), JsonUtil.stringfy(songyangJi));</span><br><span class="line">     <span class="type">User</span> <span class="variable">u</span> <span class="operator">=</span> JsonUtil.parse((String) redisTemplate.opsForValue().get(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()), User.class);</span><br><span class="line">     System.out.println(u);</span><br><span class="line">     u.setName(<span class="string">&quot;gong chen bo&quot;</span>);</span><br><span class="line">     <span class="type">BoundValueOperations</span> <span class="variable">valueOps</span> <span class="operator">=</span> redisTemplate.boundValueOps(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId());</span><br><span class="line">     valueOps.set(JsonUtil.stringfy(u));</span><br><span class="line">     System.out.println(redisTemplate.opsForValue().get(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>



<h3 id="测试-HyperLogLog"><a href="#测试-HyperLogLog" class="headerlink" title="测试 HyperLogLog"></a>测试 HyperLogLog</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">    <span class="keyword">void</span> <span class="title function_">testHyperLogLog</span><span class="params">()</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 使用HyperLogLog统计每天登录的用户量</span></span><br><span class="line">        <span class="keyword">final</span> <span class="type">long</span> <span class="variable">userId</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextLong();</span><br><span class="line"><span class="comment">//        final long userId = 1L;</span></span><br><span class="line">        <span class="type">HyperLogLogOperations</span> <span class="variable">hyperLogLog</span> <span class="operator">=</span> redisTemplate.opsForHyperLogLog();</span><br><span class="line">        <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> <span class="string">&quot;user:login:number:&quot;</span> + LocalDate.now();</span><br><span class="line">        hyperLogLog.add(key, userId);</span><br><span class="line">        System.out.println(hyperLogLog.size(key));</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<h3 id="测试-BitMap"><a href="#测试-BitMap" class="headerlink" title="测试 BitMap"></a>测试 BitMap</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">testBitMap</span><span class="params">()</span> &#123;</span><br><span class="line">  </span><br><span class="line">     <span class="comment">// 示例：使用BitMap记录用户本周是否有签到</span></span><br><span class="line">     <span class="keyword">final</span> <span class="type">long</span> <span class="variable">userId</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextLong();</span><br><span class="line">     <span class="comment">// final long userId = 1L;</span></span><br><span class="line">     <span class="comment">// userId高48位用于将用户划分到不同的key，低16位作为位图偏移参数offset;</span></span><br><span class="line">     <span class="type">String</span> <span class="variable">keySign</span> <span class="operator">=</span> <span class="string">&quot;user:sign:&quot;</span> + LocalDate.now().getDayOfWeek() + <span class="string">&quot;:&quot;</span> + (userId &gt;&gt; <span class="number">16</span>);</span><br><span class="line">     <span class="comment">// offset参数必须大于或等于0，小于2^32(bit 映射被限制在 512 MB 之内)</span></span><br><span class="line">     redisTemplate.opsForValue().setBit(keySign, userId &amp; <span class="number">0xffff</span>, <span class="literal">true</span>);</span><br><span class="line">     System.out.println(<span class="string">&quot;是否签到：&quot;</span> + redisTemplate.opsForValue().getBit(keySign, userId &amp; <span class="number">0xffff</span>));</span><br><span class="line">     System.out.println(<span class="string">&quot;是否签到：&quot;</span> + redisTemplate.opsForValue().getBit(keySign, (userId + <span class="number">1</span>) &amp; <span class="number">0xffff</span>));</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>



<h3 id="测试-Lua"><a href="#测试-Lua" class="headerlink" title="测试 Lua"></a>测试 Lua</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">void</span> <span class="title function_">testLua</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="type">User</span> <span class="variable">songyangJi</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">12345L</span>, <span class="string">&quot;SongyangJi&quot;</span>, <span class="number">18</span>, <span class="number">73.5</span>, <span class="number">0</span>, LocalDate.now().minusDays(<span class="number">1</span>));</span><br><span class="line">    <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_hash_key</span> <span class="operator">=</span> <span class="string">&quot;user&quot;</span>;</span><br><span class="line">    <span class="comment">// 使用Hash结构，map传入</span></span><br><span class="line">    redisTemplate.opsForHash().putAll(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), BeanAndMapConvertUtil.beanToMap(songyangJi));</span><br><span class="line">    System.out.println(redisTemplate.opsForHash().entries(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 构造 lua脚本</span></span><br><span class="line">    DefaultRedisScript&lt;String&gt; script = <span class="keyword">new</span> <span class="title class_">DefaultRedisScript</span>&lt;&gt;();</span><br><span class="line">    script.setLocation(<span class="keyword">new</span> <span class="title class_">ClassPathResource</span>(<span class="string">&quot;lua-script/user-sign.lua&quot;</span>)); <span class="comment">// 设置脚本所在位置，也可以直接把脚本内容放在字符串里</span></span><br><span class="line">    script.setResultType(String.class); <span class="comment">// 必须设置返回值类型（否则 execute 返回值为 null ）</span></span><br><span class="line"></span><br><span class="line">    List&lt;String&gt; keys = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    keys.add(String.valueOf(songyangJi.getUserId()));</span><br><span class="line">    keys.add(LocalDate.now().toString());</span><br><span class="line"></span><br><span class="line">    System.out.println(<span class="string">&quot;签到成功与否：&quot;</span>+redisTemplate.execute(script, keys));</span><br><span class="line">    System.out.println(<span class="string">&quot;签到成功与否：&quot;</span>+redisTemplate.execute(script, keys));</span><br><span class="line">    System.out.println(redisTemplate.opsForHash().entries(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>resources&#x2F;lua-script&#x2F;user-sign.lua</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">local</span> score = redis.call(<span class="string">&#x27;hget&#x27;</span>, <span class="string">&#x27;user:&#x27;</span> .. KEYS[<span class="number">1</span>], <span class="string">&#x27;score&#x27;</span>)</span><br><span class="line"><span class="keyword">local</span> day = redis.call(<span class="string">&#x27;hget&#x27;</span>, <span class="string">&#x27;user:&#x27;</span> .. KEYS[<span class="number">1</span>], <span class="string">&#x27;lastSignDay&#x27;</span>)</span><br><span class="line"><span class="keyword">if</span> (day == KEYS[<span class="number">2</span>]) <span class="keyword">then</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;0&#x27;</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    redis.call(<span class="string">&#x27;hset&#x27;</span>, <span class="string">&#x27;user:&#x27;</span> .. KEYS[<span class="number">1</span>], <span class="string">&#x27;score&#x27;</span>, score + <span class="number">1</span>, <span class="string">&#x27;lastSignDay&#x27;</span>, KEYS[<span class="number">2</span>])</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&#x27;1&#x27;</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"><span class="comment">-- 在 lua 中数组的索引从 1 开始</span></span><br></pre></td></tr></table></figure>







<blockquote>
<p> 附录</p>
</blockquote>
<p>Code:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LearnRedisSpringbootApplicationTests</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    RedisTemplate redisTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">flushDB</span><span class="params">()</span> &#123;</span><br><span class="line">        Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection().flushAll();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">testString</span><span class="params">()</span> &#123;</span><br><span class="line">        flushDB();</span><br><span class="line">        redisTemplate.opsForValue().set(<span class="string">&quot;str_key&quot;</span>, <span class="string">&quot;hello_world&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">testBeanAndHash</span><span class="params">()</span> &#123;</span><br><span class="line">        flushDB();</span><br><span class="line"></span><br><span class="line">        <span class="type">User</span> <span class="variable">songyangJi</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">12345L</span>, <span class="string">&quot;SongyangJi&quot;</span>, <span class="number">18</span>, <span class="number">73.5</span>, <span class="number">0</span>, <span class="literal">null</span>);</span><br><span class="line">        <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_hash_key</span> <span class="operator">=</span> <span class="string">&quot;user_hash&quot;</span>;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_json_key</span> <span class="operator">=</span> <span class="string">&quot;user_json&quot;</span>;</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;------ 使用 Hash 存储对象 ------&quot;</span>);</span><br><span class="line">        <span class="comment">// 使用Hash结构，map传入</span></span><br><span class="line">        redisTemplate.opsForHash().putAll(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), BeanAndMapConvertUtil.beanToMap(songyangJi));</span><br><span class="line"></span><br><span class="line">        <span class="type">BoundHashOperations</span> <span class="variable">hashOs</span> <span class="operator">=</span> redisTemplate.boundHashOps(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId());</span><br><span class="line">        System.out.println(hashOs.get(<span class="string">&quot;userId&quot;</span>));</span><br><span class="line">        System.out.println(hashOs.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">        hashOs.put(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;gong chen bo&quot;</span>);</span><br><span class="line">        hashOs.increment(<span class="string">&quot;age&quot;</span>, <span class="number">1</span>);</span><br><span class="line">        System.out.println(hashOs.keys());</span><br><span class="line">        System.out.println(hashOs.values());</span><br><span class="line">        System.out.println(hashOs.entries());</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;------- 使用 Json 存储对象 -------&quot;</span>);</span><br><span class="line">        redisTemplate.opsForValue().set(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), JsonUtil.stringfy(songyangJi));</span><br><span class="line">        <span class="type">User</span> <span class="variable">u</span> <span class="operator">=</span> JsonUtil.parse((String) redisTemplate.opsForValue().get(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()), User.class);</span><br><span class="line">        System.out.println(u);</span><br><span class="line">        u.setName(<span class="string">&quot;gong chen bo&quot;</span>);</span><br><span class="line">        <span class="type">BoundValueOperations</span> <span class="variable">valueOps</span> <span class="operator">=</span> redisTemplate.boundValueOps(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId());</span><br><span class="line">        valueOps.set(JsonUtil.stringfy(u));</span><br><span class="line">        System.out.println(redisTemplate.opsForValue().get(user_json_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">testBitMap</span><span class="params">()</span> &#123;</span><br><span class="line">        flushDB();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 示例：使用BitMap记录用户本周是否有签到</span></span><br><span class="line">        <span class="keyword">final</span> <span class="type">long</span> <span class="variable">userId</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextLong();</span><br><span class="line">        <span class="comment">// final long userId = 1L;</span></span><br><span class="line">        <span class="comment">// userId高48位用于将用户划分到不同的key，低16位作为位图偏移参数offset;</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">keySign</span> <span class="operator">=</span> <span class="string">&quot;user:sign:&quot;</span> + LocalDate.now().getDayOfWeek() + <span class="string">&quot;:&quot;</span> + (userId &gt;&gt; <span class="number">16</span>);</span><br><span class="line">        <span class="comment">// offset参数必须大于或等于0，小于2^32(bit 映射被限制在 512 MB 之内)</span></span><br><span class="line">        redisTemplate.opsForValue().setBit(keySign, userId &amp; <span class="number">0xffff</span>, <span class="literal">true</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;是否签到：&quot;</span> + redisTemplate.opsForValue().getBit(keySign, userId &amp; <span class="number">0xffff</span>));</span><br><span class="line">        System.out.println(<span class="string">&quot;是否签到：&quot;</span> + redisTemplate.opsForValue().getBit(keySign, (userId + <span class="number">1</span>) &amp; <span class="number">0xffff</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">testHyperLogLog</span><span class="params">()</span> &#123;</span><br><span class="line">        flushDB();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 使用HyperLogLog统计每天登录的用户量</span></span><br><span class="line">        <span class="keyword">final</span> <span class="type">long</span> <span class="variable">userId</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>().nextLong();</span><br><span class="line"><span class="comment">//        final long userId = 1L;</span></span><br><span class="line">        <span class="type">HyperLogLogOperations</span> <span class="variable">hyperLogLog</span> <span class="operator">=</span> redisTemplate.opsForHyperLogLog();</span><br><span class="line">        <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> <span class="string">&quot;user:login:number:&quot;</span> + LocalDate.now();</span><br><span class="line">        hyperLogLog.add(key, userId);</span><br><span class="line">        System.out.println(hyperLogLog.size(key));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">testLua</span><span class="params">()</span> &#123;</span><br><span class="line">        flushDB();</span><br><span class="line"></span><br><span class="line">        <span class="type">User</span> <span class="variable">songyangJi</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>(<span class="number">12345L</span>, <span class="string">&quot;SongyangJi&quot;</span>, <span class="number">18</span>, <span class="number">73.5</span>, <span class="number">0</span>, LocalDate.now().minusDays(<span class="number">1</span>));</span><br><span class="line">        <span class="keyword">final</span> <span class="type">String</span> <span class="variable">user_hash_key</span> <span class="operator">=</span> <span class="string">&quot;user&quot;</span>;</span><br><span class="line">        <span class="comment">// 使用Hash结构，map传入</span></span><br><span class="line">        redisTemplate.opsForHash().putAll(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId(), BeanAndMapConvertUtil.beanToMap(songyangJi));</span><br><span class="line">        System.out.println(redisTemplate.opsForHash().entries(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 构造 lua脚本</span></span><br><span class="line">        DefaultRedisScript&lt;String&gt; script = <span class="keyword">new</span> <span class="title class_">DefaultRedisScript</span>&lt;&gt;();</span><br><span class="line">        script.setLocation(<span class="keyword">new</span> <span class="title class_">ClassPathResource</span>(<span class="string">&quot;lua-script/user-sign.lua&quot;</span>)); <span class="comment">// 设置脚本所在位置，也可以直接把脚本内容放在字符串里</span></span><br><span class="line">        script.setResultType(String.class); <span class="comment">// 必须设置返回值类型（否则 execute 返回值为 null ）</span></span><br><span class="line"></span><br><span class="line">        List&lt;String&gt; keys = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        keys.add(String.valueOf(songyangJi.getUserId()));</span><br><span class="line">        keys.add(LocalDate.now().toString());</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;签到成功与否：&quot;</span>+redisTemplate.execute(script, keys));</span><br><span class="line">        System.out.println(<span class="string">&quot;签到成功与否：&quot;</span>+redisTemplate.execute(script, keys));</span><br><span class="line">        System.out.println(redisTemplate.opsForHash().entries(user_hash_key + <span class="string">&quot;:&quot;</span> + songyangJi.getUserId()));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/25/%E5%8F%8D%E5%B0%84%E7%9A%84%E5%9F%BA%E7%A1%80%E3%80%81Class%E3%80%81Field%E3%80%81Method%E3%80%81Constructor%E7%B1%BB/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/25/%E5%8F%8D%E5%B0%84%E7%9A%84%E5%9F%BA%E7%A1%80%E3%80%81Class%E3%80%81Field%E3%80%81Method%E3%80%81Constructor%E7%B1%BB/" class="post-title-link" itemprop="url">反射的基础、Class、Field、Method、Constructor类</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-25 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-25T00:00:00+08:00">2021-09-25</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-01-04 22:52:19" itemprop="dateModified" datetime="2023-01-04T22:52:19+08:00">2023-01-04</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <blockquote>
<p>简单的介绍一下反射的概念。为框架的学习打下基础。</p>
</blockquote>
<h1 id="反射概念"><a href="#反射概念" class="headerlink" title="反射概念"></a>反射概念</h1><p>反射可以在运行时动态分析类，解析一个类的构造器、字段、方法、接口等等。<br>反射有何作用，或者说为什么要学习反射？<br>作为应用程序员，一般情况下，并不直接使用反射，它更多在构建系统级程序时发挥用处，如实现Java的Spring框架、持久层框架Mybatis时，反射的使用处处可见。Java的其他特性或技术也依赖于反射，如代理（Proxy）等等。</p>
<p>所以，学习反射，很大程度上并不是让我们直接使用反射，而是更好地理解框架的实现，更好地操纵框架。</p>
<blockquote>
<p> Java反射的应用很多，如，JSON的序列化&#x2F;反序列化，JDK动态代理，AOP等等</p>
</blockquote>
<h1 id="Class-类"><a href="#Class-类" class="headerlink" title="Class 类"></a>Class 类</h1><p>我们知道一个类有一些基本要素构成，如<br><strong>构造器、成员变量（字段）、成员方法</strong>等等。<br>那么这些信息如何描述呢？或者说，一个类本身的信息用什么类去描述呢？</p>
<p><strong>Class类就是用来描述类本身的信息的</strong>。</p>
<p>因为一个类的信息有很多，这里就不把Class类完整的分析一下了。<br>这里这分析最易理解，也是类的最基本的元素信息。</p>
<p>源码分析。</p>
<p>下面是<code>Class</code>类中的一些方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 返回类的名字</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> ;</span><br><span class="line"><span class="comment">// 获取类及超类的公共字段、方法、构造器</span></span><br><span class="line"><span class="keyword">public</span> Field[] getFields();</span><br><span class="line"><span class="keyword">public</span> Method[] getMethods();</span><br><span class="line"><span class="keyword">public</span> Constructor[] getConstructors();</span><br><span class="line"><span class="comment">// 返回特定的字段、方法、构造器</span></span><br><span class="line"><span class="keyword">public</span> Field <span class="title function_">getField</span><span class="params">(String name)</span>;</span><br><span class="line"><span class="keyword">public</span> Method <span class="title function_">getMethod</span><span class="params">(String name, Class&lt;?&gt;... parameterTypes)</span>;</span><br><span class="line"><span class="keyword">public</span> Constructor&lt;T&gt; <span class="title function_">getConstructor</span><span class="params">(Class&lt;?&gt;... parameterTypes)</span>;</span><br></pre></td></tr></table></figure>

<p>既然Class是一个类，如何获得它的实例对象。</p>
<ol>
<li><p>object.getClass()</p>
</li>
<li><p>T.class</p>
</li>
<li><p>Class.forName(className)</p>
</li>
</ol>
<p>例如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Student student;</span><br><span class="line"><span class="type">Class</span> <span class="variable">studentClass1</span> <span class="operator">=</span> student.getClass();</span><br><span class="line"><span class="type">Class</span> <span class="variable">studentClass2</span> <span class="operator">=</span> Student.class;</span><br><span class="line"><span class="type">Class</span> <span class="variable">studentClass3</span> <span class="operator">=</span> Class.forName(<span class="string">&quot;Student&quot;</span>);</span><br></pre></td></tr></table></figure>


<p>在<code>java.lang.reflect</code>包里，有三个类值得关注，就Class描述类本身信息类似，也许有特定的三个类去描述<strong>构造器、字段、方法</strong>。</p>
<p>而且这三个类具有共性,因为其实都是类的成员。<br>所以类中的方法都类似。</p>
<p><img src="/2021/09/25/%E5%8F%8D%E5%B0%84%E7%9A%84%E5%9F%BA%E7%A1%80%E3%80%81Class%E3%80%81Field%E3%80%81Method%E3%80%81Constructor%E7%B1%BB/extends.png" alt="类图"></p>
<p>实现的<code>Member</code>接口中的部分方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 返回声明这个字段、构造器、方法的类</span></span><br><span class="line"><span class="keyword">public</span> Class&lt;?&gt; getDeclaringClass();</span><br><span class="line"><span class="comment">// 返回这个字段、构造器、方法的名字</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span>;</span><br><span class="line"><span class="comment">// 返回这个字段、构造器、方法的修饰符</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getModifiers</span><span class="params">()</span>;</span><br></pre></td></tr></table></figure>

<h2 id="Field-类"><a href="#Field-类" class="headerlink" title="Field 类"></a>Field 类</h2><p>三个很重要的方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 返回字段类型</span></span><br><span class="line">Class <span class="title function_">getType</span><span class="params">()</span>;</span><br><span class="line"><span class="comment">// 返回字段名字（标识符）</span></span><br><span class="line">String <span class="title function_">getName</span><span class="params">()</span>;</span><br><span class="line"><span class="comment">// 返回某个对象的这个字段的值。</span></span><br><span class="line">Object <span class="title function_">get</span><span class="params">(obj)</span>;</span><br><span class="line"><span class="comment">// 给对象赋值</span></span><br><span class="line">set(Object obj,Object value);</span><br></pre></td></tr></table></figure>


<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">	<span class="comment">// 这里必须是public,否则是不可达的（当然也可以强制设置为accessible）</span></span><br><span class="line">    <span class="keyword">public</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Student</span><span class="params">(String name, <span class="type">int</span> age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Student</span> <span class="variable">student</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Student</span>(<span class="string">&quot;Mike&quot;</span>, <span class="number">18</span>);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">cl</span> <span class="operator">=</span> Student.class;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">Field</span> <span class="variable">nameField</span> <span class="operator">=</span> cl.getField(<span class="string">&quot;name&quot;</span>);</span><br><span class="line">            System.out.println(<span class="string">&quot;字段名字: &quot;</span> + nameField.getName());</span><br><span class="line">            <span class="type">Class</span> <span class="variable">fieldType</span> <span class="operator">=</span> nameField.getType();</span><br><span class="line">            System.out.println(<span class="string">&quot;字段类型: &quot;</span> + fieldType);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">filedValue</span> <span class="operator">=</span> nameField.get(student);</span><br><span class="line">            System.out.println(<span class="string">&quot;字段的值: &quot;</span> + filedValue);</span><br><span class="line">            nameField.set(student,<span class="string">&quot;Jack&quot;</span>);</span><br><span class="line">            System.out.println(student.name);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchFieldException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IllegalAccessException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>在c&#x2F;c++语言中，有方法指针（其实就是函数的入口地址）传给函数做参数。<br>但是Java的设计者认为这是不安全的，所以没有显示的方法指针。</p>
<p>Java提供的解决方案是接口和lambda表达式。</p>
<p>但是这里的Method对象，也可以提供像函数指针的效果。</p>
<h2 id="Method-类"><a href="#Method-类" class="headerlink" title="Method 类"></a>Method 类</h2><p>与上面类似，有几个关键的方法值得注意。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 根据方法名和参数列表获得方法句柄</span></span><br><span class="line">Method <span class="title function_">getMethod</span><span class="params">(String name,Class... parameterTypes)</span>;</span><br><span class="line"><span class="comment">// 第一个参数为隐式参数，后面的方法的显示参数</span></span><br><span class="line"><span class="comment">// 如果是静态方法，第一个参数为null即可</span></span><br><span class="line">invoke(Object obj,Object... args);</span><br></pre></td></tr></table></figure>
<p>例子：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Student</span><span class="params">(String name, <span class="type">int</span> age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setAge</span><span class="params">(<span class="type">int</span> age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">show</span><span class="params">()</span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;show information&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Student</span> <span class="variable">student</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Student</span>(<span class="string">&quot;Mike&quot;</span>, <span class="number">18</span>);</span><br><span class="line">        <span class="type">Class</span> <span class="variable">cl</span> <span class="operator">=</span> Student.class;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 实例有参方法</span></span><br><span class="line">            <span class="type">Method</span> <span class="variable">setAgeMethod</span> <span class="operator">=</span> cl.getMethod(<span class="string">&quot;setAge&quot;</span>, <span class="type">int</span>.class) ;</span><br><span class="line">            setAgeMethod.invoke(student,<span class="number">28</span>);</span><br><span class="line">            System.out.println(student.age);</span><br><span class="line">            <span class="comment">// 静态无参方法</span></span><br><span class="line">            <span class="type">Method</span> <span class="variable">showMethod</span> <span class="operator">=</span> cl.getMethod(<span class="string">&quot;show&quot;</span>);</span><br><span class="line">            showMethod.invoke(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IllegalAccessException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InvocationTargetException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这种方法调用的缺点是明显的。<br>一是，参数和返回值都是Object，需要来回强制转换。<br>二是，这样调用方法本身就是兜了个圈子，很耗时。</p>
<p>与Method对象类似，Constructor不过是一种特殊的方法。</p>
<h2 id="Constructor-类"><a href="#Constructor-类" class="headerlink" title="Constructor 类"></a>Constructor 类</h2><p>几个重要的方法原型。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取构造器</span></span><br><span class="line"><span class="keyword">public</span> Constructor&lt;T&gt; <span class="title function_">getConstructor</span><span class="params">(Class&lt;?&gt;... parameterTypes)</span>;</span><br><span class="line"><span class="comment">// 根据构造器生成实例</span></span><br><span class="line"><span class="keyword">public</span> T <span class="title function_">newInstance</span><span class="params">(Object ... initargs)</span></span><br></pre></td></tr></table></figure>
<p>举例。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.InvocationTargetException;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> String name;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> age;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Student</span><span class="params">(String name, <span class="type">int</span> age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.name = name;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Student&#123;&quot;</span> +</span><br><span class="line">                <span class="string">&quot;name=&#x27;&quot;</span> + name + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                <span class="string">&quot;, age=&quot;</span> + age +</span><br><span class="line">                <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test2</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">cl</span> <span class="operator">=</span> Student.class;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> cl.getConstructor(String.class,<span class="type">int</span>.class);</span><br><span class="line">            <span class="type">Student</span> <span class="variable">student</span> <span class="operator">=</span> (Student) constructor.newInstance(<span class="string">&quot;Jack&quot;</span>,<span class="number">18</span>);</span><br><span class="line">            System.out.println(student);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>




<p>附：《Java核心技术卷》书上的源代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> about_reflect;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Field;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Modifier;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ClassAnalyzer</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> Class cl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ClassAnalyzer</span><span class="params">(Class clazz)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.cl = clazz;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 输出所有的构造器（包括 private 、 protected）</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">printConstructors</span><span class="params">()</span> &#123;</span><br><span class="line">        Constructor[] constructors = cl.getDeclaredConstructors();</span><br><span class="line">        <span class="keyword">for</span>(Constructor c:constructors)&#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">name</span> <span class="operator">=</span> c.getName();</span><br><span class="line">            System.out.print(<span class="string">&quot;    &quot;</span>);</span><br><span class="line">            <span class="type">String</span> <span class="variable">modifiers</span> <span class="operator">=</span> Modifier.toString(c.getModifiers());</span><br><span class="line">            <span class="keyword">if</span>(modifiers.length()&gt;<span class="number">0</span>) System.out.print(modifiers+<span class="string">&quot; &quot;</span>);</span><br><span class="line">            System.out.print(name+<span class="string">&quot;(&quot;</span>);</span><br><span class="line"></span><br><span class="line">            Class[] paramTypes = c.getParameterTypes();</span><br><span class="line">            <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j&lt;paramTypes.length;j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(j&gt;<span class="number">0</span>) System.out.print(<span class="string">&quot;, &quot;</span>);</span><br><span class="line">                System.out.print(paramTypes[j].getName());</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            System.out.println(<span class="string">&quot;);&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 输出在这个类中的所有的方法</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">printMethods</span><span class="params">()</span> &#123;</span><br><span class="line">        Method[] methods = cl.getDeclaredMethods();</span><br><span class="line">        <span class="keyword">for</span>(Method m:methods)&#123;</span><br><span class="line">            <span class="type">Class</span> <span class="variable">retype</span> <span class="operator">=</span> m.getReturnType();</span><br><span class="line">            <span class="type">String</span> <span class="variable">methodName</span> <span class="operator">=</span> m.getName();</span><br><span class="line">            System.out.print(<span class="string">&quot;    &quot;</span>);</span><br><span class="line">            <span class="type">String</span> <span class="variable">modifiers</span> <span class="operator">=</span> Modifier.toString(m.getModifiers());</span><br><span class="line">            <span class="keyword">if</span>(modifiers.length()&gt;<span class="number">0</span>)&#123;</span><br><span class="line">                System.out.print(modifiers+<span class="string">&quot; &quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.print(retype.getName()+<span class="string">&quot; &quot;</span>+methodName+<span class="string">&quot;(&quot;</span>);</span><br><span class="line">            Class[] params = m.getParameterTypes();</span><br><span class="line">            <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j&lt;params.length;j++)&#123;</span><br><span class="line">                <span class="keyword">if</span>(j&gt;<span class="number">0</span>) System.out.print(<span class="string">&quot;, &quot;</span>);</span><br><span class="line">                System.out.print(params[j].getName());</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println(<span class="string">&quot;);&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 输出在这个类中的所有的字段</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">printFields</span><span class="params">()</span> &#123;</span><br><span class="line">        Field[] fields = cl.getDeclaredFields();</span><br><span class="line">        <span class="keyword">for</span>(Field field:fields) &#123;</span><br><span class="line">            System.out.print(<span class="string">&quot;    &quot;</span>);</span><br><span class="line">            <span class="type">Class</span> <span class="variable">type</span> <span class="operator">=</span> field.getType();</span><br><span class="line">            <span class="type">String</span> <span class="variable">modifiers</span> <span class="operator">=</span> Modifier.toString(field.getModifiers());</span><br><span class="line">            <span class="keyword">if</span>(modifiers.length()&gt;<span class="number">0</span>) System.out.print(modifiers+<span class="string">&quot; &quot;</span>);</span><br><span class="line">            System.out.println(type.getName()+<span class="string">&quot; &quot;</span>+field.getName()+<span class="string">&quot;;&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">display</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">Class</span> <span class="variable">supercl</span> <span class="operator">=</span> cl.getSuperclass();</span><br><span class="line">        <span class="type">String</span> <span class="variable">modifiers</span> <span class="operator">=</span> Modifier.toString(cl.getModifiers());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(modifiers.length()&gt;<span class="number">0</span>) System.out.print(modifiers+<span class="string">&quot; &quot;</span>);</span><br><span class="line">        System.out.print(<span class="string">&quot;class &quot;</span>+cl.getName());</span><br><span class="line">        <span class="keyword">if</span>(supercl != <span class="literal">null</span> &amp;&amp; supercl != Object.class)&#123;</span><br><span class="line">            System.out.print(<span class="string">&quot; extends &quot;</span>+supercl.getName());</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(<span class="string">&quot; &#123;\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">        printFields();</span><br><span class="line"></span><br><span class="line">        printConstructors();</span><br><span class="line"></span><br><span class="line">        printMethods();</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;&#125;&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>测试代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> about_reflect.ClassAnalyzer;</span><br><span class="line"><span class="keyword">import</span> java.util.Scanner;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span>(<span class="type">var</span> <span class="variable">in</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(System.in))&#123;</span><br><span class="line">            ClassAnalyzer classAnalyzer;</span><br><span class="line">            <span class="type">String</span> <span class="variable">classname</span> <span class="operator">=</span> in.next();</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                classAnalyzer = <span class="keyword">new</span> <span class="title class_">ClassAnalyzer</span>(Class.forName(classname));</span><br><span class="line">            &#125; <span class="keyword">catch</span> (ClassNotFoundException e) &#123;</span><br><span class="line">                System.out.println(<span class="string">&quot;此类未找到&quot;</span>);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            classAnalyzer.display();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 运行结果为：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line">java.lang.String</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">java</span>.lang.String &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> [B value;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">byte</span> coder;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> hash;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> serialVersionUID;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">boolean</span> COMPACT_STRINGS;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> [Ljava.io.ObjectStreamField; serialPersistentFields;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> java.util.Comparator CASE_INSENSITIVE_ORDER;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">byte</span> LATIN1;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">byte</span> UTF16;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, <span class="type">int</span>, <span class="type">int</span>);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, java.nio.charset.Charset);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, java.lang.String);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, <span class="type">int</span>, <span class="type">int</span>, java.nio.charset.Charset);</span><br><span class="line">    java.lang.String([C, <span class="type">int</span>, <span class="type">int</span>, java.lang.Void);</span><br><span class="line">    java.lang.String(java.lang.AbstractStringBuilder, java.lang.Void);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String(java.lang.StringBuilder);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String(java.lang.StringBuffer);</span><br><span class="line">    java.lang.String([B, <span class="type">byte</span>);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([C, <span class="type">int</span>, <span class="type">int</span>);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([C);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String(java.lang.String);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String();</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, <span class="type">int</span>, <span class="type">int</span>, java.lang.String);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, <span class="type">int</span>);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([B, <span class="type">int</span>, <span class="type">int</span>, <span class="type">int</span>);</span><br><span class="line">    <span class="keyword">public</span> java.lang.String([I, <span class="type">int</span>, <span class="type">int</span>);</span><br><span class="line"></span><br><span class="line">    [B <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equals</span><span class="params">(java.lang.Object)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">length</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">toString</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">hashCode</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">getChars</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>, [C, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">volatile</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(java.lang.Object)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">(java.lang.String, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">([B, <span class="type">byte</span>, <span class="type">int</span>, java.lang.String, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">indexOf</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">checkIndex</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">float</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">boolean</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">long</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">double</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(java.lang.Object)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">(<span class="type">char</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">([C)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">valueOf</span><span class="params">([C, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="type">byte</span> <span class="title function_">coder</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> java.lang.Void <span class="title function_">rangeCheck</span><span class="params">([C, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.util.stream.IntStream <span class="title function_">codePoints</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isEmpty</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">char</span> <span class="title function_">charAt</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">codePointAt</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">codePointBefore</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">codePointCount</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">offsetByCodePoints</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> [B <span class="title function_">getBytes</span><span class="params">(java.nio.charset.Charset)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">getBytes</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>, [B, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> [B <span class="title function_">getBytes</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> [B <span class="title function_">getBytes</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">getBytes</span><span class="params">([B, <span class="type">int</span>, <span class="type">byte</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contentEquals</span><span class="params">(java.lang.StringBuffer)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contentEquals</span><span class="params">(java.lang.CharSequence)</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">nonSyncContentEquals</span><span class="params">(java.lang.AbstractStringBuilder)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">equalsIgnoreCase</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareToIgnoreCase</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">regionMatches</span><span class="params">(<span class="type">boolean</span>, <span class="type">int</span>, java.lang.String, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">regionMatches</span><span class="params">(<span class="type">int</span>, java.lang.String, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">startsWith</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">startsWith</span><span class="params">(java.lang.String, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">endsWith</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">([B, <span class="type">byte</span>, <span class="type">int</span>, java.lang.String, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">(java.lang.String, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lastIndexOf</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">substring</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">substring</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.CharSequence <span class="title function_">subSequence</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">concat</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">replace</span><span class="params">(java.lang.CharSequence, java.lang.CharSequence)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">replace</span><span class="params">(<span class="type">char</span>, <span class="type">char</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">matches</span><span class="params">(java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">contains</span><span class="params">(java.lang.CharSequence)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">replaceFirst</span><span class="params">(java.lang.String, java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">replaceAll</span><span class="params">(java.lang.String, java.lang.String)</span>;</span><br><span class="line">    <span class="keyword">public</span> [Ljava.lang.String; split(java.lang.String);</span><br><span class="line">    <span class="keyword">public</span> [Ljava.lang.String; split(java.lang.String, <span class="type">int</span>);</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">transient</span> java.lang.String <span class="title function_">join</span><span class="params">(java.lang.CharSequence, [Ljava.lang.CharSequence;)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">join</span><span class="params">(java.lang.CharSequence, java.lang.Iterable)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">toLowerCase</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">toLowerCase</span><span class="params">(java.util.Locale)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">toUpperCase</span><span class="params">(java.util.Locale)</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">toUpperCase</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">trim</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">strip</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">stripLeading</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">stripTrailing</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isBlank</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> <span class="title function_">indexOfNonWhitespace</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.util.stream.Stream <span class="title function_">lines</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.util.stream.IntStream <span class="title function_">chars</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> [C <span class="title function_">toCharArray</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">transient</span> java.lang.String <span class="title function_">format</span><span class="params">(java.lang.String, [Ljava.lang.Object;)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">transient</span> java.lang.String <span class="title function_">format</span><span class="params">(java.util.Locale, java.lang.String, [Ljava.lang.Object;)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">copyValueOf</span><span class="params">([C, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> java.lang.String <span class="title function_">copyValueOf</span><span class="params">([C)</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">native</span> java.lang.String <span class="title function_">intern</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">public</span> java.lang.String <span class="title function_">repeat</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">isLatin1</span><span class="params">()</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">checkOffset</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">checkBoundsOffCount</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">checkBoundsBeginEnd</span><span class="params">(<span class="type">int</span>, <span class="type">int</span>, <span class="type">int</span>)</span>;</span><br><span class="line">    <span class="keyword">static</span> java.lang.String <span class="title function_">valueOfCodePoint</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Process finished with exit code <span class="number">0</span></span><br></pre></td></tr></table></figure>


<p>先介绍这么多，以后再补。</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/23/%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90c%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%EF%BC%9F%E2%80%94%E2%80%94-Argtable3%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/23/%E5%A6%82%E4%BD%95%E8%A7%A3%E6%9E%90c%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%EF%BC%9F%E2%80%94%E2%80%94-Argtable3%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/" class="post-title-link" itemprop="url">如何解析c语言程序的命令行参数？—— Argtable3使用教程</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2021-09-23 00:00:00 / 修改时间：07:20:52" itemprop="dateCreated datePublished" datetime="2021-09-23T00:00:00+08:00">2021-09-23</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="如何构建符合-POSIX-实用程序约定的Shell-CLI"><a href="#如何构建符合-POSIX-实用程序约定的Shell-CLI" class="headerlink" title="如何构建符合 POSIX 实用程序约定的Shell-CLI"></a>如何构建符合 POSIX 实用程序约定的Shell-CLI</h1><h2 id="What-is-Argtable"><a href="#What-is-Argtable" class="headerlink" title="What is Argtable"></a>What is Argtable</h2><p>Argtable是一款开源的ANSI C library，用来解析GNU样式的命令行选项。它通过定义可用于指定命令行语法的声明式API，从而简化了命令行的分析。<br>argtable将自动生成一致的错误处理逻辑和命令行语法的文本描述，这对于一个健壮的cli程序来说，是非常必要的，但是很繁琐。</p>
<h2 id="Introduction-of-Argtable3"><a href="#Introduction-of-Argtable3" class="headerlink" title="Introduction of Argtable3"></a>Introduction of Argtable3</h2><p>解析程序的命令行一直以来都是一个分散注意力的主要编程任务。Argtable3 库通过允许程序员<strong>将源代码中的命令行选项直接定义为静态的结构数组</strong>来简化作业， 然后**<br>将该数组传递给argtable3库函数，这些函数就会相应地解析命令行。从命令行中提取的值直接保存到用户定义的程序变量中<strong>，主程序就可以访问这些变量。<br>argtable3还可以从同一数组中生成命令行语法的描述，以便显示为联机帮助。根据第三条BSD许可条款，此库是免费的。 注意：</strong>argtable3不向后兼容**。</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="demo-code"><a href="#demo-code" class="headerlink" title="demo code"></a>demo code</h3><ul>
<li><p>入门小例子</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 引入 argtable3</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;argtable3.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* global arg_xxx structs */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span> *<span class="title">help</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_end</span> *<span class="title">end</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> &#123;</span><br><span class="line">    <span class="comment">/* the global arg_xxx structs are initialised within the argtable */</span></span><br><span class="line">    <span class="type">void</span> *argtable[] = &#123;</span><br><span class="line">            help = arg_litn(<span class="literal">NULL</span>, <span class="string">&quot;help&quot;</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;display this help and exit&quot;</span>),</span><br><span class="line">            end = arg_end(<span class="number">20</span>)</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">int</span> exitcode = <span class="number">0</span>;</span><br><span class="line">    <span class="type">char</span> program[] = <span class="string">&quot;argtable&quot;</span>;</span><br><span class="line">    arg_parse(argc, argv, argtable);</span><br><span class="line">    <span class="comment">/* special case: &#x27;--help&#x27; takes precedence over error reporting */</span></span><br><span class="line">    <span class="keyword">if</span> (help-&gt;count &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Usage: %s&quot;</span>, program);</span><br><span class="line">        arg_print_syntax(<span class="built_in">stdout</span>, argtable, <span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;Demonstrate command-line parsing in argtable3.\n\n&quot;</span>);</span><br><span class="line">        arg_print_glossary(<span class="built_in">stdout</span>, argtable, <span class="string">&quot;  %-25s %s\n&quot;</span>);</span><br><span class="line">        exitcode = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">/* deallocate each non-null entry in argtable[] */</span></span><br><span class="line">        arg_freetable(argtable, <span class="keyword">sizeof</span>(argtable) / <span class="keyword">sizeof</span>(argtable[<span class="number">0</span>]));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> exitcode;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>运行</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">./argtable --help</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">输出</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Usage: argtable [--<span class="built_in">help</span>]</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">Demonstrate command-line parsing <span class="keyword">in</span> argtable3.</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"><span class="comment">#  --help                    display this help and exit</span></span></span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="how-it-works"><a href="#how-it-works" class="headerlink" title="how it works"></a>how it works</h3><p>Argtable3 提供了一组<strong>arg_xxx结构</strong>，一个用于它支持的每种类型的参数（<strong>文字、整数、双精度、字符串、文件名</strong>等），<br>并且每个结构都能够在命令行上处理该参数的多次出现。此外，<strong>可以为每个选项提供可互换使用的替代短选项 (-x)或长选项 (–xx) 形式</strong>。<br>事实上，每个选项甚至可以选择多个替代的短选项或长选项，或两者兼而有之。</p>
<p>要定义命令行选项，您必须为arg_xxx所需的每种类型的参数（<strong>文字、整数、双精度、字符串、文件名</strong>等）创建一个结构体，并将它们整理到我们称为参数表（<strong>argument table</strong>）的数组中。<br>参数表中结构的顺序定义了命令行选项的预期顺序，不过<strong>解析顺序实际上只对未标记的选项重要</strong>（和python的函数传参规则类似）。<br><strong>参数表本身只是一个void指针数组</strong>（<code>void* arg_table[]</code>），<br>按照惯例，每个arg_xxx结构都有一个已知的<strong>arg_hdr结构体</strong>作为其第一个条目，Argtable3 函数使用它来标识结构体。</p>
<h4 id="arg-hdr"><a href="#arg-hdr" class="headerlink" title="arg_hdr"></a>arg_hdr</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> &#123;</span></span><br><span class="line">    <span class="type">char</span> flag;             <span class="comment">/* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* shortopts; <span class="comment">/* String defining the short options */</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* longopts;  <span class="comment">/* String defiing the long options */</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* datatype;  <span class="comment">/* Description of the argument data type */</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span>* glossary;  <span class="comment">/* Description of the option as shown by arg_print_glossary function */</span></span><br><span class="line">    <span class="type">int</span> mincount;          <span class="comment">/* Minimum number of occurences of this option accepted */</span></span><br><span class="line">    <span class="type">int</span> maxcount;          <span class="comment">/* Maximum number of occurences if this option accepted */</span></span><br><span class="line">    <span class="type">void</span>* parent;          <span class="comment">/* Pointer to parent arg_xxx struct */</span></span><br><span class="line">    arg_resetfn* resetfn;  <span class="comment">/* Pointer to parent arg_xxx reset function */</span></span><br><span class="line">    arg_scanfn* scanfn;    <span class="comment">/* Pointer to parent arg_xxx scan function */</span></span><br><span class="line">    arg_checkfn* checkfn;  <span class="comment">/* Pointer to parent arg_xxx check function */</span></span><br><span class="line">    arg_errorfn* errorfn;  <span class="comment">/* Pointer to parent arg_xxx error function */</span></span><br><span class="line">    <span class="type">void</span>* priv;            <span class="comment">/* Pointer to private header data for use by arg_xxx functions */</span></span><br><span class="line">&#125; <span class="type">arg_hdr_t</span>;</span><br></pre></td></tr></table></figure>
<p>最基本的一个类型，所有的其他类型都包含这个类型。一一解释下里面的参数的含义:</p>
<ul>
<li>shortopts: 参数的短名称，比如ls -a 中的a就是短名称;</li>
<li>longopts: 参数中的长名称，比如ls —all 中的all就是长名称;</li>
<li>datatype: 参数的数据类型有, , NULL, ,(时间类型传入format字符串),(rex类型传入匹配串),等;</li>
<li>glossary: 对于参数的描述;</li>
<li>mincount: 参数最少的个数(可以规定是否必须有参数比如设置为0为非必须，1…n为必须);</li>
<li>maxcount: 参数最多的个数，采用Unix风格的，如kernel.exe -l 1 -l 2 -l 3</li>
<li>其他参数非必须。</li>
</ul>
<h4 id="arg-xxx结构体族"><a href="#arg-xxx结构体族" class="headerlink" title="arg_xxx结构体族"></a>arg_xxx结构体族</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 整数</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_int</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">int</span> *ival;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 文字</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 双精度浮点数</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_dbl</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">double</span> *dval;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 字符串</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_str</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> **sval;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_rex</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> **sval;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_file</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> **filename;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> **basename;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> **extension;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_date</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *format;</span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">tm</span> *<span class="title">tm_val</span>;</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h4 id="详细介绍-arg-int"><a href="#详细介绍-arg-int" class="headerlink" title="详细介绍 arg_int"></a>详细介绍 arg_int</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_int</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">arg_hdr</span> <span class="title">hdr</span>;</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    <span class="type">int</span> *ival;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>结构体的第一个数据成员hdr保存了 Argtable3 库函数使用的私有数据。它包含参数的标签字符串等内容（<strong>可以理解为元数据</strong>）。<br>直接公开地访问这些数据是可以的，但很少需要这样做。<br>它的ival成员变量指向持有从命令行提取出的数组，count为数组的长度。ival 数组的存储在arg_int构造时分配。<br><strong>这必须通过arg_int构造函数完成。</strong><br>注意，<strong>你永远不应该自己手动实例化任何arg_xxx结构，而是始终使用提供的构造函数来分配结构，并在完成后使用 arg_freetable 释放它。</strong></p>
<ul>
<li>举例<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_int</span> *<span class="title">s</span>;</span></span><br><span class="line">s = arg_intn(<span class="literal">NULL</span>, <span class="string">&quot;scalar&quot;</span>, <span class="string">&quot;&lt;n&gt;&quot;</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="string">&quot;foo value&quot;</span>);</span><br></pre></td></tr></table></figure>
完成s后将指向一个包含5 个元素数组的内存块的结构体arg_int。<br>甚至，你还可以设置多个别名，短选项被赋予一串单个字符，而长选项被赋予一个逗号分隔的字符串。<br>例如：<code>s = arg_intn(&quot;kKx&quot;, &quot;scalar,foo&quot;, &quot;&lt;n&gt;&quot;, 3, 5, &quot;foo value&quot;);</code></li>
</ul>
<p><img src="/example.png" alt="example.png"><br>如图所示，该<code>s-&gt;hdr</code>结构保留对构造函数的字符串参数的引用等。<br>该<code>s-&gt;count</code>变量初始化为零，因为它表示<code>s-&gt;ival</code>解析命令行后存储在数组中的有效值的数量。<br><code>s-&gt;ival</code>数组的大小由<code>s-&gt;hdr.maxcount</code>给出。</p>
<ul>
<li>实例代码<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 引入 argtable3</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;argtable3.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* global arg_xxx structs */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_int</span> *<span class="title">int_arrays</span>;</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_end</span> *<span class="title">end</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span> &#123;</span><br><span class="line">    <span class="comment">/* the global arg_xxx structs are initialised within the argtable */</span></span><br><span class="line">    <span class="type">void</span> *argtable[] = &#123;</span><br><span class="line">            int_arrays = arg_intn(<span class="string">&quot;a&quot;</span>, <span class="string">&quot;array&quot;</span>, <span class="string">&quot;&lt;number&gt;&quot;</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="string">&quot;please input an integer&quot;</span>),</span><br><span class="line">            end = arg_end(<span class="number">20</span>)</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="type">int</span> exitcode = <span class="number">-1</span>;</span><br><span class="line">    <span class="type">int</span> nerrors = arg_parse(argc, argv, argtable);</span><br><span class="line">    <span class="keyword">if</span> (nerrors == <span class="number">0</span>) &#123;</span><br><span class="line">        exitcode = <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> *a = int_arrays-&gt;ival;</span><br><span class="line">        <span class="type">int</span> len = int_arrays-&gt;count;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;input numbers are as following:\n&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; len; ++i) &#123;</span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;%d  &quot;</span>, a[i]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> exitcode;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">运行</span></span><br><span class="line">./argtable -a 1 -a 2 --array 3</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">输出</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">input numbers are as following:</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">1  2  3</span>  </span><br></pre></td></tr></table></figure></li>
</ul>
<p>其他的参数结构体使用方法大同小异。</p>
<h4 id="The-Argument-Table-参数表"><a href="#The-Argument-Table-参数表" class="headerlink" title="The Argument Table (参数表)"></a>The Argument Table (参数表)</h4><p>在构建完各种类型参数的结构体之后，我们需要统一将它们组装到一个结构体数组里面，类型为<code>void **</code>。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span> *<span class="title">a</span> =</span> arg_litn(<span class="string">&quot;a&quot;</span>, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;the -a option&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span> *<span class="title">b</span> =</span> arg_litn(<span class="string">&quot;b&quot;</span>, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;the -b option&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span> *<span class="title">c</span> =</span> arg_litn(<span class="string">&quot;c&quot;</span>, <span class="literal">NULL</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;the -c option&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_int</span> *<span class="title">scal</span> =</span> arg_intn(<span class="literal">NULL</span>, <span class="string">&quot;scalar&quot;</span>, <span class="string">&quot;&lt;n&gt;&quot;</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;foo value&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_lit</span> *<span class="title">verb</span> =</span> arg_litn(<span class="string">&quot;v&quot;</span>, <span class="string">&quot;verbose&quot;</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;verbose output&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_file</span> *<span class="title">o</span> =</span> arg_filen(<span class="string">&quot;o&quot;</span>, <span class="literal">NULL</span>,<span class="string">&quot;myfile&quot;</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="string">&quot;output file&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_file</span> *<span class="title">file</span> =</span> arg_filen(<span class="literal">NULL</span>, <span class="literal">NULL</span>, <span class="string">&quot;&lt;file&gt;&quot;</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="string">&quot;input files&quot;</span>);</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">arg_end</span> *<span class="title">end</span> =</span> arg_end(<span class="number">20</span>);</span><br><span class="line"><span class="comment">// 这就是我们的参数列表</span></span><br><span class="line"><span class="type">void</span> *argtable[] = &#123;a, b, c, scal, verb, o, file, end&#125;; </span><br></pre></td></tr></table></figure>

<p>其中，<code>arg_end</code> 结构体是一个特殊的结构体，因为它不代表任何命令行选项。<br>它主要标记 argtable 数组的结尾，同时它也存储在处理命令行参数时遇到的任何解析器错误。<br>传递给arg_end构造函数的整数参数是它将存储的最大错误数，任何更多的错误都将被丢弃并替换为单个错误消息“错误太多”。<br><strong><code>arg_end</code>必须要有。</strong></p>
<p>你还可以使用<code>arg_nullcheck</code>检查参数表中是否有空指针，（感觉这个功能很鸡肋）</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (arg_nullcheck(argtable) != <span class="number">0</span>)</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;error: insufficient memory\n&quot;</span>);</span><br></pre></td></tr></table></figure>

<h4 id="解析命令行"><a href="#解析命令行" class="headerlink" title="解析命令行"></a>解析命令行</h4><p>我们使用<code>arg_parse</code>函数来做到这一点，它返回它遇到的解析错误的数量。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> nerrors = arg_parse(argc, argv, argtable);</span><br></pre></td></tr></table></figure>
<p>如果没有错误的话（<code>nerrors == 0</code>），那么我们已经成功解析了命令行,你想要在命令行中提取的数据也都存在了参数表这个<code>void**</code>里面，正常地访问它即可。</p>
<h4 id="设置默认值"><a href="#设置默认值" class="headerlink" title="设置默认值"></a>设置默认值</h4><p>对此的解决方法很简单，直接在调用<code>arg_parse</code>之前设置<code>arg_table</code>的值，在命令行中有用户输入的值才会被覆盖。<br>其余的，就是你一开始设置的默认值。</p>
<h4 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h4><p>如果 arg_parse 函数报告错误，那么我们需要显示它们，因为 arg_parse 本身不会这样做。<br>使用<code>arg_print_errors</code>即可，arg_end的内部结构无需关心。<br>函数定义</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">arg_print_errors</span><span class="params">(FILE* fp, <span class="keyword">struct</span> arg_end* end, <span class="type">const</span> <span class="type">char</span>* progname)</span>;</span><br></pre></td></tr></table></figure>
<p>使用实例如：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">If (nerrors &gt; <span class="number">0</span>)</span><br><span class="line">    arg_print_errors(<span class="built_in">stdout</span>, end, <span class="string">&quot;myprog&quot;</span>); <span class="comment">// stdout 文件描述符</span></span><br></pre></td></tr></table></figure>
<p>arg_parse函数不打印错误消息是因为它可以被多次调用以使用替代参数表解析命令行，而不会过早显示无关的错误消息。<br>因此，我们可以为那些具有互斥命令行选项集的程序定义单独的参数表，依次尝试每个参数表，直到找到一个成功的候选者。<br>如果所有参数表都不能满足，那么我们可以选择打印所有参数表的错误消息，或者可能只显示与最匹配的错误信息。无论如何，我们可以控制显示哪些消息。</p>
<h4 id="显示选项语法及帮助"><a href="#显示选项语法及帮助" class="headerlink" title="显示选项语法及帮助"></a>显示选项语法及帮助</h4><p>如果您希望您的程序显示在线帮助，您可以使用<code>arg_print_syntax</code>函数来显示从参数表派生的命令行语法。<br>该函数实际上有两种形式：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">arg_print_syntax</span><span class="params">(FILE *fp, <span class="type">void</span> **argtable, <span class="type">const</span> <span class="type">char</span> *suffix)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">arg_print_syntaxv</span><span class="params">(FILE *fp, <span class="type">void</span> **argtable, <span class="type">const</span> <span class="type">char</span> *suffix)</span>;</span><br></pre></td></tr></table></figure>
<p>你可以使用<code>void arg_print_glossary(FILE *fp, void **argtable, const char *format);</code>来输出提示。</p>
<p>在文章的开始的示例中已经展示过这两个函数的使用方法了，这里不再赘述。</p>
<h4 id="打扫干净"><a href="#打扫干净" class="headerlink" title="打扫干净"></a>打扫干净</h4><p>在我们的程序结束时，我们需要释放分配给每个arg_xxx结构的内存。我们可以通过分别调用<code>arg_freetable</code>来做到这一点，<br>但有函数可以更方便地为我们做到这一点。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arg_freetable(argtable, <span class="keyword">sizeof</span>(argtable) / <span class="keyword">sizeof</span>(argtable[<span class="number">0</span>]));</span><br></pre></td></tr></table></figure>
<p>它将遍历一个参数表并代表我们调用它的每个元素。<br>请注意，第二个参数<code>sizeof(argtable)/sizeof(argtable[0])</code>仅表示 argtable 数组中的元素数。（使用了内存对齐？）<br>完成此功能后，所有 argtable 数组条目都将设置为NULL。</p>
<h3 id="完整的使用Argtable3的流程图"><a href="#完整的使用Argtable3的流程图" class="headerlink" title="完整的使用Argtable3的流程图"></a>完整的使用Argtable3的流程图</h3><p><img src="/flowchart.png" alt="流程图"></p>
<h2 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h2><p><a target="_blank" rel="noopener" href="https://www.argtable.org/tutorial/">Argtable3教程介绍</a><br><a target="_blank" rel="noopener" href="https://github.com/argtable/argtable3/releases/">github地址</a></p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/16/Redis%E5%9C%A8Java%20%E8%AF%AD%E8%A8%80%E7%9A%84%E4%BD%BF%E7%94%A8%20%E2%80%94%E2%80%94%20%E4%BD%BF%E7%94%A8%20Jedis%20%E6%B5%8B%E8%AF%95%20redis%E6%93%8D%E7%BA%B5%E5%87%A0%E7%A7%8D%E5%B8%B8%E8%A7%81%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%91%BD%E4%BB%A4/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/16/Redis%E5%9C%A8Java%20%E8%AF%AD%E8%A8%80%E7%9A%84%E4%BD%BF%E7%94%A8%20%E2%80%94%E2%80%94%20%E4%BD%BF%E7%94%A8%20Jedis%20%E6%B5%8B%E8%AF%95%20redis%E6%93%8D%E7%BA%B5%E5%87%A0%E7%A7%8D%E5%B8%B8%E8%A7%81%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%91%BD%E4%BB%A4/" class="post-title-link" itemprop="url">Redis在Java 语言的使用 —— 使用 Jedis 测试 redis操纵几种常见数据类型的命令</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-16 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-16T00:00:00+08:00">2021-09-16</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-12-01 10:19:48" itemprop="dateModified" datetime="2021-12-01T10:19:48+08:00">2021-12-01</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Redis/" itemprop="url" rel="index"><span itemprop="name">Redis</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="Jedis"><a href="#Jedis" class="headerlink" title="Jedis"></a>Jedis</h1><h2 id="Jedis介绍"><a href="#Jedis介绍" class="headerlink" title="Jedis介绍"></a>Jedis介绍</h2><p>Jedis 是 Redis 官方首选的 Java 客户端开发包。</p>
<h2 id="如何使用"><a href="#如何使用" class="headerlink" title="如何使用"></a>如何使用</h2><p>三样东西必不可少：</p>
<ol>
<li>jdk</li>
<li>redis-server</li>
<li>java的redis驱动</li>
</ol>
<p>我没有直接使用jar包导入，而是采用maven。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- https://mvnrepository.com/artifact/redis.clients/jedis --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>redis.clients<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jedis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.3.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在终端打开 redis-server之后：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PingJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="comment">//连接本地的 Redis 服务</span></span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        <span class="comment">// 如果 Redis 服务设置来密码，需要下面这行，没有就不需要</span></span><br><span class="line">        <span class="comment">// jedis.auth(&quot;123456&quot;);</span></span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line"></span><br><span class="line"><span class="comment">//        System.out.println(&quot;终止Redis服务:&quot;+jedis.shutdown());</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>如果正常返回 <code>pong</code>，说明我们已经可以在java里使用redis了；</p>
<h2 id="测试string"><a href="#测试string" class="headerlink" title="测试string"></a>测试string</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StringInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line"><span class="comment">//       测试 set、get</span></span><br><span class="line">        jedis.set(<span class="string">&quot;name&quot;</span>,<span class="string">&quot;Ji&quot;</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line">        <span class="comment">// 测试 get 不存在的键</span></span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;non-exist&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//       测试增量 incr incrBy</span></span><br><span class="line">        jedis.incr(<span class="string">&quot;num&quot;</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;num&quot;</span>));</span><br><span class="line">        jedis.incrBy(<span class="string">&quot;num&quot;</span>,<span class="number">2</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;num&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试增量 incr incrBy</span></span><br><span class="line">        jedis.decr(<span class="string">&quot;num&quot;</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;num&quot;</span>));</span><br><span class="line">        jedis.decrBy(<span class="string">&quot;num&quot;</span>,<span class="number">2</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;num&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试浮点数的增量</span></span><br><span class="line">        jedis.incrByFloat(<span class="string">&quot;num&quot;</span>,<span class="number">9.9</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;num&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试追加功能</span></span><br><span class="line">        jedis.append(<span class="string">&quot;name&quot;</span>,<span class="string">&quot; Songyang&quot;</span>);</span><br><span class="line">        System.out.println(jedis.get(<span class="string">&quot;name&quot;</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//        获取字符串长度</span></span><br><span class="line">        System.out.println(jedis.strlen(<span class="string">&quot;name&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        一次性获取多个值</span></span><br><span class="line">        List&lt;String&gt; values = jedis.mget(<span class="string">&quot;name&quot;</span>,<span class="string">&quot;num&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span>(String val:values) System.out.println(val);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line">Ji</span><br><span class="line"><span class="literal">null</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">3</span></span><br><span class="line"><span class="number">2</span></span><br><span class="line"><span class="number">0</span></span><br><span class="line"><span class="number">9.90000000000000036</span></span><br><span class="line">Ji Songyang</span><br><span class="line"><span class="number">11</span></span><br><span class="line">Ji Songyang</span><br><span class="line"><span class="number">9.90000000000000036</span></span><br></pre></td></tr></table></figure>

<h2 id="测试hash"><a href="#测试hash" class="headerlink" title="测试hash"></a>测试hash</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HashInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 hset、hget</span></span><br><span class="line">        jedis.hset(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;color&quot;</span>,<span class="string">&quot;white&quot;</span>);</span><br><span class="line">        jedis.hset(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>,<span class="string">&quot;999998&quot;</span>);</span><br><span class="line">        System.out.println(jedis.hget(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;color&quot;</span>));</span><br><span class="line">        System.out.println(jedis.hget(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>));</span><br><span class="line"></span><br><span class="line">        Map&lt;String,String&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;kind&quot;</span>,<span class="string">&quot;bmw&quot;</span>);</span><br><span class="line">        map.put(<span class="string">&quot;owner&quot;</span>,<span class="string">&quot;jsy&quot;</span>);</span><br><span class="line">        jedis.hset(<span class="string">&quot;car&quot;</span>,map);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//       批量获取 键、值、键值对</span></span><br><span class="line">        System.out.println(jedis.hlen(<span class="string">&quot;car&quot;</span>));</span><br><span class="line">        System.out.println(jedis.hgetAll(<span class="string">&quot;car&quot;</span>));</span><br><span class="line">        Set&lt;String&gt; keySet = jedis.hkeys(<span class="string">&quot;car&quot;</span>);</span><br><span class="line">        System.out.println(keySet);</span><br><span class="line">        List&lt;String&gt; values = jedis.hvals(<span class="string">&quot;car&quot;</span>);</span><br><span class="line">        System.out.println(values);</span><br><span class="line"></span><br><span class="line"><span class="comment">//       测试字段是否存在</span></span><br><span class="line">        System.out.println(jedis.hexists(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>));</span><br><span class="line">        System.out.println(jedis.hexists(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;manufacturer&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 hsetnx</span></span><br><span class="line">        jedis.hsetnx(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;country&quot;</span>,<span class="string">&quot;US&quot;</span>);</span><br><span class="line">        System.out.println(jedis.hgetAll(<span class="string">&quot;car&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试给某一个字段自增</span></span><br><span class="line">        jedis.hincrBy(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>,<span class="number">1</span>);</span><br><span class="line">        jedis.hincrByFloat(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>,<span class="number">0.99</span>);</span><br><span class="line">        System.out.println(jedis.hget(<span class="string">&quot;car&quot;</span>,<span class="string">&quot;price&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 删除字段</span></span><br><span class="line">        System.out.println(jedis.hdel(<span class="string">&quot;car&quot;</span>, <span class="string">&quot;price&quot;</span>, <span class="string">&quot;non-exist-field&quot;</span>));</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line">white</span><br><span class="line"><span class="number">999998</span></span><br><span class="line"><span class="number">4</span></span><br><span class="line">&#123;color=white, owner=jsy, price=<span class="number">999998</span>, kind=bmw&#125;</span><br><span class="line">[color, owner, price, kind]</span><br><span class="line">[white, <span class="number">999998</span>, bmw, jsy]</span><br><span class="line"><span class="literal">true</span></span><br><span class="line"><span class="literal">false</span></span><br><span class="line">&#123;owner=jsy, country=US, color=white, price=<span class="number">999998</span>, kind=bmw&#125;</span><br><span class="line"><span class="number">999999.98999999999068677</span></span><br><span class="line"><span class="number">1</span></span><br></pre></td></tr></table></figure>

<h2 id="测试list"><a href="#测试list" class="headerlink" title="测试list"></a>测试list</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ListInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line"><span class="comment">//      测试 lpush、rpush</span></span><br><span class="line">        jedis.lpush(<span class="string">&quot;list&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        jedis.rpush(<span class="string">&quot;list&quot;</span>,<span class="string">&quot;3&quot;</span>,<span class="string">&quot;4&quot;</span>);</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试删除</span></span><br><span class="line">        jedis.lpop(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">        jedis.rpop(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">        System.out.println(jedis.llen(<span class="string">&quot;list&quot;</span>));</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        jedis.lpop(<span class="string">&quot;list&quot;</span>);</span><br><span class="line">        jedis.lpop(<span class="string">&quot;list&quot;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 此时 list为空</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;<span class="number">10</span>;i++) jedis.rpush(<span class="string">&quot;list&quot;</span>,<span class="string">&quot;&quot;</span>+i);</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 lrange(key,start,end);</span></span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">1</span>,<span class="number">2</span>));</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>,<span class="number">3</span>,-<span class="number">2</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//       测试线性表的get、set方法</span></span><br><span class="line">        System.out.println(jedis.lindex(<span class="string">&quot;list&quot;</span>,<span class="number">3</span>));</span><br><span class="line">        System.out.println(jedis.lindex(<span class="string">&quot;list&quot;</span>,-<span class="number">2</span>));</span><br><span class="line">        jedis.lset(<span class="string">&quot;list&quot;</span>,<span class="number">0</span>,<span class="string">&quot;10&quot;</span>);</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>, <span class="number">0</span>, -<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 list 的删除元素的功能</span></span><br><span class="line">        <span class="comment">// 按索引 保留 [start,end]</span></span><br><span class="line">        jedis.ltrim(<span class="string">&quot;list&quot;</span>,<span class="number">3</span>,<span class="number">8</span>);</span><br><span class="line">        <span class="comment">// 按元素去删</span></span><br><span class="line">        jedis.lrem(<span class="string">&quot;list&quot;</span>,<span class="number">1</span>,<span class="string">&quot;5&quot;</span>);</span><br><span class="line">        System.out.println(jedis.lrange(<span class="string">&quot;list&quot;</span>, <span class="number">0</span>, -<span class="number">1</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line">[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="number">2</span></span><br><span class="line">[<span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">[<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]</span><br><span class="line">[<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]</span><br><span class="line">[<span class="number">1</span>, <span class="number">2</span>]</span><br><span class="line">[<span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>]</span><br><span class="line"><span class="number">3</span></span><br><span class="line"><span class="number">8</span></span><br><span class="line">[<span class="number">10</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>]</span><br><span class="line">[<span class="number">3</span>, <span class="number">4</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>]</span><br></pre></td></tr></table></figure>

<h2 id="操纵set"><a href="#操纵set" class="headerlink" title="操纵set"></a>操纵set</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SetInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 sadd、srem</span></span><br><span class="line">        jedis.sadd(<span class="string">&quot;set&quot;</span>,<span class="string">&quot;1&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;3&quot;</span>,<span class="string">&quot;4&quot;</span>);</span><br><span class="line">        System.out.println(jedis.smembers(<span class="string">&quot;set&quot;</span>));</span><br><span class="line">        jedis.srem(<span class="string">&quot;set&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;5&quot;</span>);</span><br><span class="line">        System.out.println(jedis.smembers(<span class="string">&quot;set&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        元素是否在集合中</span></span><br><span class="line">        System.out.println(jedis.sismember(<span class="string">&quot;set&quot;</span>,<span class="string">&quot;2&quot;</span>));</span><br><span class="line">        System.out.println(jedis.sismember(<span class="string">&quot;set&quot;</span>,<span class="string">&quot;1&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        获取集合元素的个数</span></span><br><span class="line">        System.out.println(jedis.scard(<span class="string">&quot;set&quot;</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试集合的交集、并集、差集</span></span><br><span class="line">        <span class="comment">// 几个用于测试集合</span></span><br><span class="line">        jedis.sadd(<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;1&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;3&quot;</span>);</span><br><span class="line">        jedis.sadd(<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;1&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;4&quot;</span>);</span><br><span class="line">        jedis.sadd(<span class="string">&quot;set3&quot;</span>,<span class="string">&quot;2&quot;</span>,<span class="string">&quot;3&quot;</span>,<span class="string">&quot;6&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 并集</span></span><br><span class="line">        Set&lt;String&gt; res1 = jedis.sunion(<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        System.out.println(res1);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 交集</span></span><br><span class="line">        Set&lt;String&gt; res2 = jedis.sinter(<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        System.out.println(res2);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 差集</span></span><br><span class="line">        Set&lt;String&gt; res3 = jedis.sdiff(<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        System.out.println(res3);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 集合中间的元算，还可以存储到Redis中。</span></span><br><span class="line">        jedis.sunionstore(<span class="string">&quot;st1&quot;</span>,<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        jedis.sinterstore(<span class="string">&quot;st2&quot;</span>,<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        jedis.sdiffstore(<span class="string">&quot;st3&quot;</span>,<span class="string">&quot;set1&quot;</span>,<span class="string">&quot;set2&quot;</span>,<span class="string">&quot;set3&quot;</span>);</span><br><span class="line">        System.out.println(jedis.smembers(<span class="string">&quot;st1&quot;</span>));</span><br><span class="line">        System.out.println(jedis.smembers(<span class="string">&quot;st2&quot;</span>));</span><br><span class="line">        System.out.println(jedis.smembers(<span class="string">&quot;st3&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line">[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line">[<span class="number">1</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="literal">false</span></span><br><span class="line"><span class="literal">true</span></span><br><span class="line"><span class="number">3</span></span><br><span class="line">[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">6</span>]</span><br><span class="line">[<span class="number">2</span>]</span><br><span class="line">[]</span><br><span class="line">[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">6</span>]</span><br><span class="line">[<span class="number">2</span>]</span><br><span class="line">[]</span><br></pre></td></tr></table></figure>

<h2 id="操纵zset"><a href="#操纵zset" class="headerlink" title="操纵zset"></a>操纵zset</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Tuple;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ZSetInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试有序集合的增加功能</span></span><br><span class="line">        jedis.zadd(<span class="string">&quot;student_score&quot;</span>,<span class="number">100</span>,<span class="string">&quot;张三&quot;</span>);</span><br><span class="line">        Map&lt;String,Double&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">        map.put(<span class="string">&quot;李四&quot;</span>,<span class="number">80.0</span>);</span><br><span class="line">        map.put(<span class="string">&quot;王五&quot;</span>,<span class="number">90.0</span>);</span><br><span class="line">        map.put(<span class="string">&quot;陈二&quot;</span>,<span class="number">60.0</span>);</span><br><span class="line">        jedis.zadd(<span class="string">&quot;student_score&quot;</span>,map);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        获取有序集合某个元素的分数、排名</span></span><br><span class="line">        System.out.println(jedis.zscore(<span class="string">&quot;student_score&quot;</span>,<span class="string">&quot;李四&quot;</span>));</span><br><span class="line">        System.out.println(jedis.zrank(<span class="string">&quot;student_score&quot;</span>,<span class="string">&quot;李四&quot;</span>));</span><br><span class="line">        System.out.println(jedis.zscore(<span class="string">&quot;student_score&quot;</span>,<span class="string">&quot;张三&quot;</span>));</span><br><span class="line">        System.out.println(jedis.zrank(<span class="string">&quot;student_score&quot;</span>,<span class="string">&quot;张三&quot;</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//        按名次顺序检索元素（及其分数）</span></span><br><span class="line"></span><br><span class="line">        System.out.println();</span><br><span class="line">        System.out.println(<span class="string">&quot;按名次顺序检索元素（及其分数） ——————————————————————\n&quot;</span>);</span><br><span class="line">        <span class="comment">// 返回 索引 [0,2]的元素</span></span><br><span class="line">        System.out.println(jedis.zrange(<span class="string">&quot;student_score&quot;</span>,<span class="number">0</span>,<span class="number">2</span>));</span><br><span class="line">        <span class="comment">// 返回 索引 [1,3]的元素及分数</span></span><br><span class="line">        Set&lt;Tuple&gt; s = jedis.zrangeWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">1</span>,<span class="number">3</span>);</span><br><span class="line">        <span class="keyword">for</span>(Tuple tuple:s)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;元素： &quot;</span>+tuple.getElement()+<span class="string">&quot;      分数：&quot;</span>+tuple.getScore());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 降序返回</span></span><br><span class="line">        System.out.println(jedis.zrevrange(<span class="string">&quot;student_score&quot;</span>, <span class="number">0</span>, <span class="number">2</span>));</span><br><span class="line">        System.out.println(jedis.zrevrangeWithScores(<span class="string">&quot;student_score&quot;</span>, <span class="number">1</span>, <span class="number">3</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        按分数范围检索元素</span></span><br><span class="line">        System.out.println();</span><br><span class="line">        System.out.println(<span class="string">&quot;按分数范围检索元素 ————————————————————  \n&quot;</span>);</span><br><span class="line">        <span class="comment">// 获取分数在 [80,100]的元素</span></span><br><span class="line">        System.out.println(jedis.zrangeByScore(<span class="string">&quot;student_score&quot;</span>,<span class="number">80</span>,<span class="number">100</span>));</span><br><span class="line">        <span class="comment">// 降序返回</span></span><br><span class="line">        System.out.println(jedis.zrevrangeByScore(<span class="string">&quot;student_score&quot;</span>, <span class="number">100</span>, <span class="number">80</span>));</span><br><span class="line">        <span class="comment">// 获取分数在 [80,100]的元素（包括分数）</span></span><br><span class="line">        System.out.println(jedis.zrangeByScoreWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">80</span>,<span class="number">100</span>));</span><br><span class="line">        <span class="comment">// 降序返回</span></span><br><span class="line">        System.out.println(jedis.zrevrangeByScoreWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">100</span>,<span class="number">80</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 返回分数大于等于70的，从第2个元素开始，且不超过2个元素，</span></span><br><span class="line">        System.out.println(jedis.zrangeByScoreWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">70</span>,Integer.MAX_VALUE,<span class="number">1</span>,<span class="number">2</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        返回有序集合的基数</span></span><br><span class="line">        System.out.println(jedis.zcard(<span class="string">&quot;student_score&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">//        统计分数在 [min,max]的元素的个数</span></span><br><span class="line">        System.out.println(jedis.zcount(<span class="string">&quot;student_score&quot;</span>, <span class="number">75</span>, <span class="number">95</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//        测试 删除元素的功能</span></span><br><span class="line">        System.out.println(<span class="string">&quot;直接删除、按排名范围删除、按分数范围删除&quot;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;当前有元素：  &quot;</span>+jedis.zrangeWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 直接删除</span></span><br><span class="line">        jedis.zrem(<span class="string">&quot;student_score&quot;</span>,<span class="string">&quot;张三&quot;</span>);</span><br><span class="line">        System.out.println(jedis.zrangeWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 按照排名范围删除</span></span><br><span class="line">        jedis.zremrangeByRank(<span class="string">&quot;student_score&quot;</span>,<span class="number">1</span>,<span class="number">1</span>);</span><br><span class="line">        System.out.println(jedis.zrangeWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 按分数范围删除</span></span><br><span class="line">        jedis.zremrangeByScore(<span class="string">&quot;student_score&quot;</span>,<span class="number">70</span>,<span class="number">95</span>);</span><br><span class="line">        System.out.println(jedis.zrangeWithScores(<span class="string">&quot;student_score&quot;</span>,<span class="number">0</span>,-<span class="number">1</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 有序集合的集合之间的操作 （ 并、交、差 ） 类似 集合之间的操作,这里略去</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line"><span class="number">80.0</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">100.0</span></span><br><span class="line"><span class="number">3</span></span><br><span class="line"></span><br><span class="line">按名次顺序检索元素（及其分数） ——————————————————————</span><br><span class="line"></span><br><span class="line">[陈二, 李四, 王五]</span><br><span class="line">元素： 李四      分数：<span class="number">80.0</span></span><br><span class="line">元素： 王五      分数：<span class="number">90.0</span></span><br><span class="line">元素： 张三      分数：<span class="number">100.0</span></span><br><span class="line">[张三, 王五, 李四]</span><br><span class="line">[[王五,<span class="number">90.0</span>], [李四,<span class="number">80.0</span>], [陈二,<span class="number">60.0</span>]]</span><br><span class="line"></span><br><span class="line">按分数范围检索元素 ————————————————————  </span><br><span class="line"></span><br><span class="line">[李四, 王五, 张三]</span><br><span class="line">[张三, 王五, 李四]</span><br><span class="line">[[李四,<span class="number">80.0</span>], [王五,<span class="number">90.0</span>], [张三,<span class="number">100.0</span>]]</span><br><span class="line">[[张三,<span class="number">100.0</span>], [王五,<span class="number">90.0</span>], [李四,<span class="number">80.0</span>]]</span><br><span class="line">[[王五,<span class="number">90.0</span>], [张三,<span class="number">100.0</span>]]</span><br><span class="line"><span class="number">4</span></span><br><span class="line"><span class="number">2</span></span><br><span class="line">直接删除、按排名范围删除、按分数范围删除</span><br><span class="line">当前有元素：  [[陈二,<span class="number">60.0</span>], [李四,<span class="number">80.0</span>], [王五,<span class="number">90.0</span>], [张三,<span class="number">100.0</span>]]</span><br><span class="line">[[陈二,<span class="number">60.0</span>], [李四,<span class="number">80.0</span>], [王五,<span class="number">90.0</span>]]</span><br><span class="line">[[陈二,<span class="number">60.0</span>], [王五,<span class="number">90.0</span>]]</span><br><span class="line">[[陈二,<span class="number">60.0</span>]]</span><br></pre></td></tr></table></figure>


<h2 id="测试HyperLogLog"><a href="#测试HyperLogLog" class="headerlink" title="测试HyperLogLog"></a>测试HyperLogLog</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashSet;</span><br><span class="line"><span class="keyword">import</span> java.util.Random;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HyperLogLog</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span>+jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 随机插入 1E8 个数字，看一下 HyperLogLog 的准确率</span></span><br><span class="line">        <span class="type">Random</span> <span class="variable">random</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>();</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">N</span> <span class="operator">=</span> (<span class="type">int</span>)<span class="number">1e6</span>;</span><br><span class="line">        <span class="type">int</span> <span class="variable">gap</span> <span class="operator">=</span> (<span class="type">int</span>)<span class="number">1e5</span> , n = (<span class="type">int</span>)<span class="number">1e5</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(n&lt;=N)&#123;</span><br><span class="line">            Set&lt;Integer&gt; set = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line">            jedis.del(<span class="string">&quot;hp&quot;</span>);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;n;i++)&#123;</span><br><span class="line">                <span class="type">int</span> <span class="variable">x</span> <span class="operator">=</span> random.nextInt();</span><br><span class="line">                set.add(x);</span><br><span class="line">                jedis.pfadd(<span class="string">&quot;hp&quot;</span>,Integer.toString(x));</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            System.out.println(<span class="string">&quot;真实数据是 &quot;</span>+set.size()+<span class="string">&quot;个不同的数&quot;</span>);</span><br><span class="line">            System.out.println(<span class="string">&quot;HyperLogLog 统计数据为 &quot;</span>+jedis.pfcount(<span class="string">&quot;hp&quot;</span>)+<span class="string">&quot;个不同的数&quot;</span>);</span><br><span class="line">            <span class="type">double</span> <span class="variable">rate</span> <span class="operator">=</span> <span class="number">1.0</span>*Math.abs(jedis.pfcount(<span class="string">&quot;hp&quot;</span>)-set.size())/set.size();</span><br><span class="line">            System.out.println(<span class="string">&quot;误差率为：&quot;</span>+rate);</span><br><span class="line">            System.out.println();</span><br><span class="line">            n += gap;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>


<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">连接成功</span><br><span class="line">服务正在运行: PONG</span><br><span class="line">——————————————————————————————————————————</span><br><span class="line">真实数据是 <span class="number">99999</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">100268</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.002690026900269003</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">199997</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">200718</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.003605054075811137</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">299989</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">297310</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.008930327445339663</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">399981</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">394993</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.012470592353136774</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">499974</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">497927</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.004094212899070752</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">599960</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">592881</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.011799119941329423</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">699948</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">697609</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.003341676810277335</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">799939</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">797154</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.0034815154655542485</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">899907</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">912082</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.01352917579260968</span></span><br><span class="line"></span><br><span class="line">真实数据是 <span class="number">999889</span>个不同的数</span><br><span class="line">HyperLogLog 统计数据为 <span class="number">998794</span>个不同的数</span><br><span class="line">误差率为：<span class="number">0.0010951215584929926</span></span><br><span class="line"></span><br><span class="line">Process finished with exit code <span class="number">0</span></span><br><span class="line">  </span><br></pre></td></tr></table></figure>



<h2 id="测试-Bitmap"><a href="#测试-Bitmap" class="headerlink" title="测试 Bitmap"></a>测试 Bitmap</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BitMapInJedis</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Jedis</span> <span class="variable">jedis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Jedis</span>(<span class="string">&quot;localhost&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;连接成功&quot;</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;服务正在运行: &quot;</span> + jedis.ping());</span><br><span class="line">        System.out.println(<span class="string">&quot;——————————————————————————————————————————&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//        先清空一下</span></span><br><span class="line">        jedis.flushAll();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">final</span> <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> <span class="string">&quot;key_bitmap&quot;</span>;</span><br><span class="line"></span><br><span class="line">        jedis.setbit(key,<span class="number">0</span>,<span class="literal">true</span>);</span><br><span class="line">        jedis.setbit(<span class="string">&quot;key_bitmap&quot;</span>,<span class="number">1</span>,<span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(key+<span class="number">1</span>+<span class="string">&quot; :&quot;</span>+jedis.getbit(key, <span class="number">1</span>));</span><br><span class="line">        System.out.println(key+<span class="number">2</span>+<span class="string">&quot; : &quot;</span>+jedis.getbit(key, <span class="number">2</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 只允许 0、1</span></span><br><span class="line">        jedis.setbit(key,<span class="number">131</span>,<span class="string">&quot;1&quot;</span>);</span><br><span class="line">        jedis.setbit(key,<span class="number">132</span>,<span class="string">&quot;0&quot;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/16/Redis%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%E7%AC%94%E8%AE%B0%20%E2%80%94%E2%80%94%20%E4%BA%8B%E5%8A%A1%EF%BC%88Transactions%EF%BC%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/16/Redis%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%E7%AC%94%E8%AE%B0%20%E2%80%94%E2%80%94%20%E4%BA%8B%E5%8A%A1%EF%BC%88Transactions%EF%BC%89/" class="post-title-link" itemprop="url">Redis官方文档笔记 —— 事务（Transactions）</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-16 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-16T00:00:00+08:00">2021-09-16</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-12-01 10:19:14" itemprop="dateModified" datetime="2021-12-01T10:19:14+08:00">2021-12-01</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Redis/" itemprop="url" rel="index"><span itemprop="name">Redis</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <p><strong>相关命令</strong></p>
<blockquote>
<p>MULTI<br>EXEC<br>DISCARD<br>WATCH<br>UNWATCH</p>
</blockquote>
<h1 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h1><p>事务是一组命令的集合。3</p>
<h2 id="性质"><a href="#性质" class="headerlink" title="性质"></a>性质</h2><ul>
<li>事务中的<strong>所有命令都被序列化并顺序执行</strong>。在Redis事务的执行过程中（指定的是 <code>exec</code>后的真正的执行过程，而不是用<code>multi</code>后的入队过程），永远不会执行另一个客户端发出的请求（**命令不会加塞）。</li>
<li>所有命令都将被执行，或者所有命令都不执行，因此<strong>Redis事务也是原子的</strong>（这句话有可能会引起争议）。</li>
</ul>
<h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>使用<code>MULTI</code>命令输入Redis事务。该命令始终以答复OK。<br>此时，用户可以发出多个命令。<strong>Redis不会执行这些命令，而是将它们排队。</strong><br><strong>一旦调用EXEC，将执行所有命令。</strong>，并且<strong>EXEC返回了一个答复数组</strong>，其中每个元素都是事务中单个命令的答复，其发出顺序与命令相同。<br>如：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; MULTI</span><br><span class="line">OK</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; SET k1 v1</span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; SET k2 v2</span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; GET k1</span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; EXEC</span><br><span class="line"><span class="number">1</span>) OK</span><br><span class="line"><span class="number">2</span>) OK</span><br><span class="line"><span class="number">3</span>) <span class="string">&quot;v1&quot;</span></span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; </span><br></pre></td></tr></table></figure>
<p>需要强调的是，<code>MULTI</code>之后的命令并不会执行，它们只是入队而已，知道<code>EXEC</code>命令发出，所有命令才会一起执行。</p>
<h2 id="事务中的错误"><a href="#事务中的错误" class="headerlink" title="事务中的错误"></a>事务中的错误</h2><h3 id="命令排队入队错误"><a href="#命令排队入队错误" class="headerlink" title="命令排队入队错误"></a>命令排队入队错误</h3><p>这种常见的错误有 ① 命令不存在 ② 命令参数的个数不对。<br>这种错误一旦发生，<strong>这个事务就会失败，也就是说事务中的命令全都不会执行</strong>。<br>如：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; multi</span><br><span class="line">OK</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; set a <span class="number">1</span></span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; get b <span class="number">1</span></span><br><span class="line">(<span class="built_in">error</span>) ERR wrong number of arguments <span class="keyword">for</span> <span class="string">&#x27;get&#x27;</span> command</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; set c <span class="number">3</span></span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; exec</span><br><span class="line">(<span class="built_in">error</span>) EXECABORT Transaction discarded because of previous errors.</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; </span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; </span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; get a</span><br><span class="line">(<span class="literal">nil</span>)</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; get c</span><br><span class="line">(<span class="literal">nil</span>)</span><br></pre></td></tr></table></figure>

<p>可见即使是正确的命令也没有执行成功。</p>
<blockquote>
<p>从Redis 2.6.5开始，服务器会记住命令累积期间发生错误，并且将拒绝执行事务，并且在EXEC期间还会返回错误并自动丢弃该事务。</p>
</blockquote>
<h3 id="命令执行错误"><a href="#命令执行错误" class="headerlink" title="命令执行错误"></a>命令执行错误</h3><p>常见的有，命令与键的类型冲突，给一个字符串类型的键自增但是键值不是数字，等等。</p>
<p>EXEC之后发生的错误不会以特殊方式处理:<strong>即使在事务期间某些命令失败，也会执行所有其他命令</strong>。<br>也正是因为一点，让Redis事务的原子性受到质疑。</p>
<p>如：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; SET a hello</span><br><span class="line">OK</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; MULTI</span><br><span class="line">OK</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; INCR a</span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; SET b <span class="number">2</span></span><br><span class="line">QUEUED</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; EXEC</span><br><span class="line"><span class="number">1</span>) (<span class="built_in">error</span>) ERR value is <span class="keyword">not</span> an integer <span class="keyword">or</span> out of range</span><br><span class="line"><span class="number">2</span>) OK</span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; GET b</span><br><span class="line"><span class="string">&quot;2&quot;</span></span><br><span class="line"><span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">6379</span>&gt; </span><br></pre></td></tr></table></figure>
<p>即使在<code>INCR</code>命令执行错误之后，可以看到之后的合法的命令仍然执行成功了。</p>
<h2 id="为什么Redis不支持回滚"><a href="#为什么Redis不支持回滚" class="headerlink" title="为什么Redis不支持回滚"></a>为什么Redis不支持回滚</h2><p>大致有三点原因：</p>
<ol>
<li>程序员自身犯的错误是无法避免的。</li>
<li>不支持回滚可以使得Redis事务的实现更加高效。</li>
<li>发生错误一般发生在开发过程中，不太可能进入到生产环境中。</li>
</ol>
<h2 id="DISCARD命令队列"><a href="#DISCARD命令队列" class="headerlink" title="DISCARD命令队列"></a>DISCARD命令队列</h2><p>之前说，一旦客户端给Redis服务器发送一个<code>MULTI</code>此时，Redis受到的命令不会立即执行，而是存储在队列里。<br>也就是此时客户端和服务器的连接状态进入一种<strong>事务状态</strong>。<br><strong>而<code>DISCARD</code>命令相反，它用来结束这种状态的，当然之前队列里的命令组也会被清空。</strong>	</p>
<p>注意，此命令只在客户端和服务器之间有<code>MULTI</code>执行之后，才会返回<strong>OK</strong>,否则返回<br><strong>(error) ERR DISCARD without MULTI</strong>。</p>
<h2 id="WATCH实现乐观锁"><a href="#WATCH实现乐观锁" class="headerlink" title="WATCH实现乐观锁"></a>WATCH实现乐观锁</h2><blockquote>
<p><code>WATCH</code>用于为Redis事务提供检查设置（CAS check-ans-set）行为。</p>
</blockquote>
<p>被WATCH的键，如果在事务执行（exec）前发生了变化，那么之后事务就不会执行，返回（null）。</p>
<p>下面的实现自增<code>INCR</code>命令组在多个客户端并发访问服务器的时候，就会产生竞争条件。<br>比如，一开始键的值的是10，向后两个客户端执行了自增命令，最终值应该是12。<br>但是，两个客户端可能先后拿到10，然后分别自增，最后分别赋值11。<br>就出现错误。</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">val = GET mykey</span><br><span class="line">val = val + <span class="number">1</span></span><br><span class="line">SET mykey $val</span><br></pre></td></tr></table></figure>

<p>可能初学者，有这样的想法，将这组命令当成一个事务执行，不就解决问题了吗。<br>不过，事务执行的结果是在<code>exec</code>之后才能拿到的，无法中途拿到（其次你也要知道的是 multi 之后也是不加任何锁的）</p>
<p>这个时候就需要<code>WATCH</code>命令了。<br>不妨换思路，</p>
<ol>
<li>监控我们需要自增的键。</li>
<li>然后获取键值，并让值加1。</li>
<li>最后用<code>set</code>命令赋值。如果，在赋值的时候，发现值已经被另一个客户端修改了，这个时候如果还去set就会出现上面的情况，所以此次事务就放弃执行。</li>
</ol>
<p><strong>基于这个思路，我们采取先check后set的方式，执行事务，如果事务失败，再执行一次，并期望这次没有产生冲突，直到这个事务执行成功。</strong><br>这种锁的形式成为<strong>乐观锁</strong>。</p>
<p>最终借助<code>WATCH</code>和事务实现了自增命令如下：</p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">WATCH mykey</span><br><span class="line">val = GET mykey</span><br><span class="line">val = val + <span class="number">1</span></span><br><span class="line">MULTI</span><br><span class="line">SET mykey $val</span><br><span class="line">EXEC</span><br></pre></td></tr></table></figure>

<p>关于<code>watch</code>命令还有如下补充：</p>
<ul>
<li><code>watch</code> 可以在<code>multi</code>之前多次调用，并且可以一次watch多个键，只要有一个键被改变，事务就不会执行。</li>
<li>当<code>exec</code>被调用时，所有键都会恢复 <strong>UNWATCHED</strong> 的状态，不管事务是否中止与否。<br>同样，当客户端连接关闭时，所有键都会被<strong>UNWATCHED</strong>。</li>
<li>也可以使用<code>unwatch</code>命令（不带参数）来刷新所有监视的键。</li>
<li>注意，很重要的一点是，<strong>键是否被监控都是相对于每个客户端而言的，也就是说它不是对于服务器的一个全局状态</strong>。以后会在Redis的实现里具体探讨。</li>
</ul>
<p>一个例子：有序集合zset是没有弹出第一个元素的原子性命令的，我们可以使用watch和事务实现它。<br><strong>使用WATCH实现ZPOP</strong></p>
<figure class="highlight lua"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">WATCH zset</span><br><span class="line">element = ZRANGE zset <span class="number">0</span> <span class="number">0</span></span><br><span class="line">MULTI</span><br><span class="line">ZREM zset element</span><br><span class="line">EXEC</span><br></pre></td></tr></table></figure>

<p>如果EXEC失败（即返回Null答复），我们将重复该操作。</p>
<h2 id="Redis脚本和事务"><a href="#Redis脚本和事务" class="headerlink" title="Redis脚本和事务"></a>Redis脚本和事务</h2><blockquote>
<p>一个Redis的脚本是定义事务性的，所以一切都可以用Redis的事务做的，你也可以用一个脚本做的，平时脚本会更简单，更快速。<br>这种重复是由于以下事实：脚本是在Redis 2.6中引入的，而事务早已存在。但是，我们不太可能在短期内取消对事务的支持，因为在语义上似乎是适当的，即使不诉诸Redis脚本，仍然有可能避免竞争状况，尤其是因为Redis事务的实现复杂性极低。<br>但是，在不久的将来，我们会看到整个用户群只是在使用脚本，这并非不可能。如果发生这种情况，我们可能会弃用并最终删除事务。</p>
</blockquote>
<h1 id="ACID"><a href="#ACID" class="headerlink" title="ACID"></a>ACID</h1><p>与关系型数据库ACID的对比。</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/16/%E5%85%B3%E4%BA%8ESpring%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%9A%84%E4%B8%80%E4%BA%9B%E6%B3%A8%E8%A7%A3/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/16/%E5%85%B3%E4%BA%8ESpring%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%9A%84%E4%B8%80%E4%BA%9B%E6%B3%A8%E8%A7%A3/" class="post-title-link" itemprop="url">关于Spring自动配置的一些注解</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-16 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-16T00:00:00+08:00">2021-09-16</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-09-27 21:00:02" itemprop="dateModified" datetime="2021-09-27T21:00:02+08:00">2021-09-27</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Spring/" itemprop="url" rel="index"><span itemprop="name">Spring</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h2 id="ConditionalXXX注解族"><a href="#ConditionalXXX注解族" class="headerlink" title="@ConditionalXXX注解族"></a>@ConditionalXXX注解族</h2><h3 id="ConditionalOnProperty"><a href="#ConditionalOnProperty" class="headerlink" title="@ConditionalOnProperty"></a>@ConditionalOnProperty</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Target(&#123; ElementType.TYPE, ElementType.METHOD &#125;)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Conditional(OnPropertyCondition.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> ConditionalOnProperty &#123;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Alias for &#123;<span class="doctag">@link</span> #name()&#125;.</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> the names</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   String[] value() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * A prefix that should be applied to each property. The prefix automatically ends</span></span><br><span class="line"><span class="comment">    * with a dot if not specified. A valid prefix is defined by one or more words</span></span><br><span class="line"><span class="comment">    * separated with dots (e.g. &#123;<span class="doctag">@code</span> &quot;acme.system.feature&quot;&#125;).</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> the prefix</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   String <span class="title function_">prefix</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The name of the properties to test. If a prefix has been defined, it is applied to</span></span><br><span class="line"><span class="comment">    * compute the full key of each property. For instance if the prefix is</span></span><br><span class="line"><span class="comment">    * &#123;<span class="doctag">@code</span> app.config&#125; and one value is &#123;<span class="doctag">@code</span> my-value&#125;, the full key would be</span></span><br><span class="line"><span class="comment">    * &#123;<span class="doctag">@code</span> app.config.my-value&#125;</span></span><br><span class="line"><span class="comment">    * &lt;p&gt;</span></span><br><span class="line"><span class="comment">    * Use the dashed notation to specify each property, that is all lower case with a &quot;-&quot;</span></span><br><span class="line"><span class="comment">    * to separate words (e.g. &#123;<span class="doctag">@code</span> my-long-property&#125;).</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> the names</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   String[] name() <span class="keyword">default</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * The string representation of the expected value for the properties. If not</span></span><br><span class="line"><span class="comment">    * specified, the property must &lt;strong&gt;not&lt;/strong&gt; be equal to &#123;<span class="doctag">@code</span> false&#125;.</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> the expected value</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   String <span class="title function_">havingValue</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line"></span><br><span class="line">   <span class="comment">/**</span></span><br><span class="line"><span class="comment">    * Specify if the condition should match if the property is not set. Defaults to</span></span><br><span class="line"><span class="comment">    * &#123;<span class="doctag">@code</span> false&#125;.</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@return</span> if should match if the property is missing</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">   <span class="type">boolean</span> <span class="title function_">matchIfMissing</span><span class="params">()</span> <span class="keyword">default</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>@ConditionalOnClass<br>@ConditionalOnBean<br>@ConditionalOnMissingBean</p>
<p>@ConditionalOnSingleCandidate</p>
<p><a target="_blank" rel="noopener" href="https://spring.hhui.top/spring-blog/2018/10/19/181019-SpringBoot%E5%9F%BA%E7%A1%80%E7%AF%87Bean%E4%B9%8B%E6%9D%A1%E4%BB%B6%E6%B3%A8%E5%85%A5-ConditionalOnProperty/">一篇很齐全的博客</a></p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/15/Redis%E7%B3%BB%E5%88%97%E7%AC%94%E8%AE%B0%E4%B9%8B%20%E2%80%94%E2%80%94%20%E9%94%AE%E3%80%81%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%81%E6%95%A3%E5%88%97%E3%80%81%E5%88%97%E8%A1%A8%E3%80%81%E9%9B%86%E5%90%88%E3%80%81%E6%9C%89%E5%BA%8F%E9%9B%86%E5%90%88%E3%80%81HyperLogLog%E7%9A%84%E6%80%A7%E8%B4%A8%E5%8F%8A%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/15/Redis%E7%B3%BB%E5%88%97%E7%AC%94%E8%AE%B0%E4%B9%8B%20%E2%80%94%E2%80%94%20%E9%94%AE%E3%80%81%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%81%E6%95%A3%E5%88%97%E3%80%81%E5%88%97%E8%A1%A8%E3%80%81%E9%9B%86%E5%90%88%E3%80%81%E6%9C%89%E5%BA%8F%E9%9B%86%E5%90%88%E3%80%81HyperLogLog%E7%9A%84%E6%80%A7%E8%B4%A8%E5%8F%8A%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/" class="post-title-link" itemprop="url">Redis系列笔记之 —— 键、字符串、散列、列表、集合、有序集合、HyperLogLog的性质及操作命令</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-15 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-15T00:00:00+08:00">2021-09-15</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-12-01 10:19:28" itemprop="dateModified" datetime="2021-12-01T10:19:28+08:00">2021-12-01</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Redis/" itemprop="url" rel="index"><span itemprop="name">Redis</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="键"><a href="#键" class="headerlink" title="键"></a>键</h1><blockquote>
<p>命令不区分大小写，尽量使用大写，表明是Redis的关键字。</p>
</blockquote>
<h2 id="获得符合规则的键名列表"><a href="#获得符合规则的键名列表" class="headerlink" title="获得符合规则的键名列表"></a>获得符合规则的键名列表</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">KEYS your_pattern</span><br></pre></td></tr></table></figure>

<p>pattern支持glob风格。</p>
<ol>
<li><code>？</code> 匹配单个字符；</li>
<li><code>*</code> 匹配任意个（包括0个）字符；</li>
<li><code>[]</code> 匹配 [] 括号间的任一字符，可以使用<code>-</code>表示范围，如a[b-d],表示匹配ab、ac、ad；</li>
<li><code>\x</code> 用于转义，匹配字符 x 本身。</li>
</ol>
<p>那么<code>KEYS *</code>实际上就会返回Redis中所有的键。</p>
<h2 id="基本命令"><a href="#基本命令" class="headerlink" title="基本命令"></a>基本命令</h2><ol>
<li><p><strong>删除</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DEL key</span><br></pre></td></tr></table></figure>
<p>存在并删除成功返回1，失败返回0；</p>
</li>
<li><p><strong>判断是否存在</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EXISTS key</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>获取类型</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TYPE key</span><br></pre></td></tr></table></figure>
<p>返回类型可能是（string字符串、hash散列、list列表、set集合、zset有序集合）</p>
</li>
<li><p>序列化给定 key</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DUMP key</span><br></pre></td></tr></table></figure>
<p>返回被序列化的值</p>
</li>
</ol>
<h2 id="生存时间相关"><a href="#生存时间相关" class="headerlink" title="生存时间相关"></a>生存时间相关</h2><ol>
<li><p>为给定 key 设置过期时间</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EXPIRE key seconds</span><br></pre></td></tr></table></figure>
<p>单位秒。</p>
</li>
<li><p>设置 key 的过期时间以毫秒计</p>
</li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PEXPIRE key milliseconds</span><br></pre></td></tr></table></figure>

<ol start="3">
<li><p>和 EXPIRE 类似</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">EXPIREAT key timestamp</span><br></pre></td></tr></table></figure>
<p>EXPIREAT 的作用和 EXPIRE 类似，都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。</p>
</li>
<li><p>和 EXPIRE 类似</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PEXPIREAT key milliseconds-timestamp</span><br></pre></td></tr></table></figure>
<p>设置 key 过期时间的时间戳(unix timestamp) 以毫秒计</p>
</li>
<li><p>移除过期时间</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PERSIST key</span><br></pre></td></tr></table></figure>
<p>移除 key 的过期时间，key 将持久保持。</p>
</li>
</ol>
<p>注意，使用<code>SET</code>、<code>GETSET</code>命令为键赋值，也会同时清除键的过期时间。<br>但是只对键值操作的命令，如（RPUSH、INCR、HSET、ZREM）</p>
<ol start="6">
<li><p>返回剩余的生存时间。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TTL key</span><br></pre></td></tr></table></figure>
<p>以<strong>秒为单位</strong>，返回给定 key 的剩余生存时间(TTL, time to live)。</p>
</li>
<li><p>和TTL类似</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PTTL key</span><br></pre></td></tr></table></figure>
<p>以<strong>毫秒为单位</strong>返回 key 的剩余的过期时间。</p>
</li>
</ol>
<h2 id="其他命令"><a href="#其他命令" class="headerlink" title="其他命令"></a>其他命令</h2><ol>
<li><p>修改 key 的名称</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RENAME key newkey</span><br></pre></td></tr></table></figure>
</li>
<li><p>仅当 newkey 不存在时，将 key 改名为 newkey 。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RENAMENX key newkey</span><br></pre></td></tr></table></figure>
</li>
<li><p>从当前数据库中随机返回一个 key</p>
</li>
</ol>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RANDOMKEY</span><br></pre></td></tr></table></figure>

<ol start="4">
<li><p>将当前数据库的 key 移动到给定的数据库 db 当中</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MOVE key db</span><br></pre></td></tr></table></figure>
</li>
<li><p>清除某个数据库的数据</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FLUSHDB</span><br></pre></td></tr></table></figure>
</li>
<li><p>清除Redis所有数据</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FLUSHALL</span><br></pre></td></tr></table></figure></li>
</ol>
<h1 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h1><h2 id="字符串-string"><a href="#字符串-string" class="headerlink" title="字符串(string)"></a>字符串(string)</h2><h3 id="性质"><a href="#性质" class="headerlink" title="性质"></a>性质</h3><ul>
<li><p>string 是 redis 最基本的类型，你可以理解成与 Memcached 一模一样的类型，一个 key 对应一个 value。</p>
</li>
<li><p>string 类型是二进制安全的。意思是 <strong>redis 的 string 可以包含任何数据</strong>。比如jpg图片或者<strong>序列化的对象</strong>。</p>
</li>
<li><p>string 类型是 Redis 最基本的数据类型，<strong>string</strong> 类型的值最大能存储 <strong>512M</strong>B。</p>
</li>
</ul>
<h3 id="操作命令"><a href="#操作命令" class="headerlink" title="操作命令"></a>操作命令</h3><ul>
<li><strong>取值赋值</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SET key value</span><br></pre></td></tr></table></figure></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GET key</span><br></pre></td></tr></table></figure>


<p>在指定的 key 不存在时，为 key 设置指定的值。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SETNX KEY_NAME VALUE</span><br></pre></td></tr></table></figure>


<ul>
<li><strong>递增递减数字</strong><br>当存储的字符串是<strong>整数形式</strong>时，可以使用<code>INCR</code>命令自增1，并返回自增后的值。<br>（当键不存在时，默认从0开始自增，所以第一次返回值为 1 ）。<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">INCR num </span><br><span class="line">返回：<span class="number">1</span></span><br><span class="line">INCR num </span><br><span class="line">返回：<span class="number">2</span></span><br></pre></td></tr></table></figure>
如果给非整数类型的值，如浮点值、字符串，使用INCR命令，会报错。<br>如：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379[1]&gt; GET s</span><br><span class="line">&quot;helloworld&quot;</span><br><span class="line">127.0.0.1:6379[1]&gt; INCR s</span><br><span class="line">(error) ERR value is not an integer or out of range</span><br></pre></td></tr></table></figure></li>
</ul>
<p><strong>指定增量</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">INCRBY key increment</span><br></pre></td></tr></table></figure>


<p>同样的，也有<strong>减少命令</strong>。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DECR key</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DECR key decrement</span><br></pre></td></tr></table></figure>

<ul>
<li><p><strong>浮点数的增加</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">INCRBYFLOAT key increment</span><br></pre></td></tr></table></figure>
<p>但没有对应的减少命令。</p>
</li>
<li><p><strong>向尾部追加值</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">APPEND key value</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>获取字符串长度</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">STRLEN key</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>同时获得&#x2F;得到多个键值</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MGET key [key ...]</span><br></pre></td></tr></table></figure>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">MSET key value [key1 value1 ...]</span><br></pre></td></tr></table></figure>
</li>
<li><p>位操作<br>暂略。</p>
</li>
</ul>
<blockquote>
<p>以下的数据类型都不能支持嵌套。</p>
</blockquote>
<h2 id="散列-hash"><a href="#散列-hash" class="headerlink" title="散列(hash)"></a>散列(hash)</h2><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><ul>
<li>Redis hash 是一个<strong>键值(key&#x3D;&gt;value)对集合</strong>。</li>
<li>键值的类型只能是<strong>字符串</strong>，也就是说不能去嵌套其他类型。</li>
<li>hash 特别适合用于<strong>存储对象</strong>。 </li>
<li>一个散列类型的键最多只能包含$2^{32}-1$（<strong>40亿</strong>多）个字段。</li>
</ul>
<h3 id="操作命令-1"><a href="#操作命令-1" class="headerlink" title="操作命令"></a>操作命令</h3><ul>
<li><strong>赋值、取值</strong></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HSET key field value</span><br><span class="line">HGET key field</span><br></pre></td></tr></table></figure>
<p>注：HSET命令不区分插入还是更新操作，插入操返回1，更新返回0；</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HMSET key field1 value1 field2 value2 [filed3 value3]</span><br><span class="line">HMGET key field1 field2 [field3]</span><br></pre></td></tr></table></figure>

<p>如果不知道散列类型的键对应的值有哪些字段，可以使用：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HGETALL</span><br></pre></td></tr></table></figure>

<ul>
<li>只获取<strong>字段名</strong>或<strong>字段值</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">HKEYS key</span><br><span class="line">HVALS key</span><br></pre></td></tr></table></figure></li>
<li>只获取<strong>字段数量</strong><br>返回字段的数量。<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HLEN key</span><br></pre></td></tr></table></figure></li>
</ul>
<p>示例：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; HSET car price 50000</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; HMSET car kind bmw color white</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; HGET car price</span><br><span class="line">&quot;50000&quot;</span><br><span class="line">127.0.0.1:6379&gt; HMGET car kind color</span><br><span class="line">1) &quot;bmw&quot;</span><br><span class="line">2) &quot;white&quot;</span><br><span class="line">127.0.0.1:6379&gt; HGETALL car</span><br><span class="line">1) &quot;price&quot;</span><br><span class="line">2) &quot;50000&quot;</span><br><span class="line">3) &quot;kind&quot;</span><br><span class="line">4) &quot;bmw&quot;</span><br><span class="line">5) &quot;color&quot;</span><br><span class="line">6) &quot;white&quot;</span><br></pre></td></tr></table></figure>


<ul>
<li><p><strong>判断字段是否存在</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HEXISTS key field</span><br></pre></td></tr></table></figure></li>
<li><p><strong>当字段不存在时赋值</strong><br>（NX表示not exists）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HSETNX key field value</span><br></pre></td></tr></table></figure>
<p>值得一提的是，这个命令也是一个原子操作，不需要担心静态条件。</p>
</li>
<li><p><strong>增加数字</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HINCRBY key filed increment</span><br></pre></td></tr></table></figure>
<p>（散列类型没有HINCR命令）</p>
</li>
<li><p><strong>删除字段</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">HDEL key field [field1 ……]</span><br></pre></td></tr></table></figure>
<p>返回成功的删除字段的个数。</p>
</li>
</ul>
<h2 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h2><h3 id="特点-1"><a href="#特点-1" class="headerlink" title="特点"></a>特点</h3><p>Redis 列表是简单的字符串列表，按照插入顺序排序。你可以添加一个元素到列表的头部（左边）或者尾部（右边）。<br>列表类型的内部使用双向链表，所以在链表两端添加元素的时间复杂度为O(1)。<br>自然，在链表两端查询元素都是很快的。</p>
<h3 id="操作命令-2"><a href="#操作命令-2" class="headerlink" title="操作命令"></a>操作命令</h3><ul>
<li><strong>向列表两端添加元素</strong></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 从左边添加（头部）</span><br><span class="line">LPUSH key val [val1 ……]</span><br><span class="line">// 从右边添加（尾部）</span><br><span class="line">RPUSH key val [val1 ……]</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>向列表两端弹出元素</strong></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">LPOP key</span><br><span class="line">RPOP key</span><br></pre></td></tr></table></figure>
<ul>
<li><strong>获取列表中元素的个数</strong></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LLEN</span><br></pre></td></tr></table></figure>
<p>当键不存在时，返回0；</p>
<ul>
<li><strong>获得列表片段</strong><br>两个注意点，① 索引<strong>从0开始</strong>， ② <strong>左右都是闭区间</strong>。<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LRANGE key start end</span><br></pre></td></tr></table></figure>
并且支持负索引，表示从右边开始计数。<br>如-1表示右边第一个，-2表示右边第二个。</li>
</ul>
<p> <strong>两个情况</strong><br>① start的位置在stop的后面，返回空列表<br>② stop的位置大于实际的索引范围，则返回到列表最右边的元素。</p>
<ul>
<li><strong>删除列表中指定的值</strong><br>REM为remove的缩写<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LREM key count value</span><br></pre></td></tr></table></figure>
删除前count个值value的元素。<br><strong>注意</strong>：<br>① count为0时，删除所有<br>②count为负，仍然删除前|count|个。</li>
</ul>
<p><strong>返回的是实际删除的元素的个数</strong>。</p>
<ul>
<li><p><strong>获得&#x2F;修改制定索引的元素值</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">LINDEX key index</span><br><span class="line">LSET KEY index value</span><br></pre></td></tr></table></figure>
<p>注意：索引从0开始</p>
</li>
<li><p><strong>只保留指定阶段</strong><br><strong>只保留[start,end]的元素</strong>，其余的元素删除。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LTRIM key start end</span><br></pre></td></tr></table></figure></li>
<li><p><strong>将元素从一个列表转到另一个列表</strong><br>将第一个列表的元素从右边弹出，从左边添加进第二的列表。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RPOPLPUSH source destination</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><h3 id="特点-2"><a href="#特点-2" class="headerlink" title="特点"></a>特点</h3><p><strong>Redis 的 Set 是 String 类型的无序集合</strong>。集合成员是<strong>唯一的</strong>，这就意味着集合中不能出现重复的数据。</p>
<p>Redis 中集合是通过<strong>哈希表 hash table</strong>实现的，所以添加，删除，查找的复杂度<strong>基本上是</strong> O(1)的。</p>
<p>集合中最大的成员数为 $2^{32}- 1$ (4294967295, 每个集合可存储40多亿个成员)。</p>
<h3 id="操作命令-3"><a href="#操作命令-3" class="headerlink" title="操作命令"></a>操作命令</h3><ul>
<li><p><strong>增加&#x2F;删除元素</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">SADD key member [member ...]</span><br><span class="line">SREM key member [member ...]</span><br></pre></td></tr></table></figure>
<p>返回是成功添加、删除的元素的个数。</p>
</li>
<li><p><strong>获得集合的所有元素</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SMEMBERS</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>判断元素是否在集合中</strong></p>
</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SISMEMBER key member</span><br></pre></td></tr></table></figure>
<p>时间复杂度为O(1)。当值存在时返回1，否则返回0。</p>
<ol>
<li><p><strong>集合的交</strong><br> intersection： 交集</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SINTER setA setB setC</span><br></pre></td></tr></table></figure></li>
<li><p><strong>集合的并</strong><br> union：并集</p>
 <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SUNION setA setB setC</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>集合的差</strong><br>首先差集$A-B$的含义是，${x| x\in A \ \ and \ \ x\notin B }$</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SDIFF key [key ....]</span><br></pre></td></tr></table></figure></li>
</ol>
<p>比如: A - B - C，依次计算即可：<br>多个集合做差集是将前两个集合差集的结果再次作为操作数。</p>
<ul>
<li><strong>获取集合中元素的个数</strong></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SCARD  key</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>进行集合运算并将结果存储</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SINTERSTORE destination key [key ...]</span><br><span class="line">SDIFFSTORE destination key [key ...]</span><br><span class="line">SUNIONSTORE destination key [key ...]</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="有序集合"><a href="#有序集合" class="headerlink" title="有序集合"></a>有序集合</h2><h3 id="特点-3"><a href="#特点-3" class="headerlink" title="特点"></a>特点</h3><ul>
<li>Redis的zset 和 set 一样也是<strong>string类型元素的集合</strong>,且<strong>不允许重复</strong>的成员。</li>
<li>不同的是<strong>每个元素都会关联一个double类型的分数</strong>。redis正是通过分数来为集合中的成员进行<strong>从小到大的排序</strong>。</li>
<li>zset的<strong>成员是唯一的</strong>,但分数(score)却可以重复。</li>
</ul>
<h3 id="操作命令-4"><a href="#操作命令-4" class="headerlink" title="操作命令"></a>操作命令</h3><ul>
<li><strong>增加元素</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZADD key score member [score member ...]</span><br></pre></td></tr></table></figure></li>
</ul>
<p>如:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZADD student_score 100 zhangsan 90 xiaoming 60 xiaohua</span><br></pre></td></tr></table></figure>

<ul>
<li><p><strong>获得元素的分数</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZSCORE  key number</span><br></pre></td></tr></table></figure>
</li>
<li><p>获得<strong>排名在某个范围</strong>的元素列表</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ZRANGE key start stop [WITHSCORES]</span><br><span class="line">ZREVRANGE key start stop [WITHSCORES]</span><br></pre></td></tr></table></figure>
<p>ZRANGE命令会按照<strong>元素分数的从小到大的顺序</strong>返回<strong>索引从start到stop之间的所有元素</strong></p>
</li>
<li><p>ZARNGE和 LRANGE类似，包括 star, stop；</p>
</li>
<li><p>如果<strong>需要同时获得元素的分数</strong>，加上参数<code>WITHSCORES</code>,</p>
</li>
<li><p>如果<strong>需要从大到小排序</strong>，用ZREVRANGE<br>如：</p>
</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; ZRANGE student_score 0 -1 WITHSCORES</span><br><span class="line">1) &quot;xiaohua&quot;</span><br><span class="line">2) &quot;60&quot;</span><br><span class="line">3) &quot;xiaoming&quot;</span><br><span class="line">4) &quot;90&quot;</span><br><span class="line">5) &quot;zhangsan&quot;</span><br><span class="line">6) &quot;100&quot;</span><br><span class="line">127.0.0.1:6379&gt; ZREVRANGE student_score 0 -1 WITHSCORES</span><br><span class="line">1) &quot;zhangsan&quot;</span><br><span class="line">2) &quot;100&quot;</span><br><span class="line">3) &quot;xiaoming&quot;</span><br><span class="line">4) &quot;90&quot;</span><br><span class="line">5) &quot;xiaohua&quot;</span><br><span class="line">6) &quot;60&quot;</span><br></pre></td></tr></table></figure>


<ul>
<li>获得<strong>指定分数范围的元素</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offser count]</span><br></pre></td></tr></table></figure></li>
</ul>
<p>该命令按照<strong>元素分数从小到大</strong>的顺序返回分数在min到max之间（包含min、max）的元素。</p>
<ul>
<li>如果需要是开区间，在min、max前面加上<code>(</code></li>
<li>min、max也可以使用<strong>无穷大</strong>，<code>+inf、-inf</code></li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LIMIT offset count</span><br></pre></td></tr></table></figure>
<p>和SQL中语法类似，offset是偏移量，count是最大允许的个数。</p>
<p>表示获取分数<strong>大于</strong>80分的从第<strong>2</strong>个人开始的3个人（不足3个就拉倒）。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZRANGEBYSCORE student_score (80 +inf WITHSCORES LIMIT  1 3</span><br></pre></td></tr></table></figure>


<ul>
<li><p><strong>增加某个元素的分数</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZINCRBY key increment member</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>获得集合中元素的数量</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZCARD key</span><br></pre></td></tr></table></figure>
</li>
<li><p>获得指定<strong>分数范围内的元素个数</strong></p>
</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZCOUNT key min max</span><br></pre></td></tr></table></figure>

<ul>
<li><p><strong>删除元素</strong><br>返回成功删除的元素个数。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZREM member [member...]</span><br></pre></td></tr></table></figure>
</li>
<li><p>按照<strong>排名范围删除元素</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZREMRANGEBYRANK key start stop</span><br></pre></td></tr></table></figure>
</li>
<li><p>按照<strong>分数范围删除元素</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZREMRANGEBYSCORE key min max</span><br></pre></td></tr></table></figure>
</li>
<li><p>按<strong>元素的排名</strong><br>从0开始，从小到大获取元素的排名，最小元素的排名为0；</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ZRANK key member</span><br></pre></td></tr></table></figure>
</li>
<li><p><strong>有序集合的交集</strong><br>暂略。</p>
</li>
</ul>
<h2 id="HyperLogLog"><a href="#HyperLogLog" class="headerlink" title="HyperLogLog"></a>HyperLogLog</h2><blockquote>
<p>基数：一个数据集中不同元素的个数。<br>基数估计：估计一个数据集中不同元素的个数，但是允许有误差。</p>
</blockquote>
<h2 id="特点-4"><a href="#特点-4" class="headerlink" title="特点"></a>特点</h2><ul>
<li><p>HyperLogLog 是用来做<strong>基数统计</strong>的算法，HyperLogLog 的优点是，在输入元素的数量或者体积非常非常大时，计算基数所需的空间总是固定 的、并且是很小的。</p>
</li>
<li><p>在 Redis 里面，<strong>每个 HyperLogLog 键只需要花费 12 KB 内存</strong>，就可以计算接近 2^64 个不同元素的基 数。这和计算基数时，元素越多耗费内存就越多的集合形成鲜明对比。</p>
</li>
<li><p>但是，因为 HyperLogLog 只会<strong>根据输入元素来计算基数</strong>，而<strong>不会储存输入元素本身</strong>，所以 HyperLogLog 不能像集合那样，返回输入的各个元素。</p>
</li>
</ul>
<h2 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h2><ul>
<li><p>将多个元素添加进<strong>HyperLogLog</strong>,但是只是统计个数，不会保存数据本身。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PFADD key element [element ...]</span><br></pre></td></tr></table></figure>

</li>
<li><p>返回数据集的基数<br>如果有多个key，会统计这些数据集的基数之和，但是注意<strong>不是简单的求和</strong>。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PFCOUNT key [key ...]</span><br></pre></td></tr></table></figure>
</li>
<li><p>将多个 HyperLogLog 合并为一个 HyperLogLog</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PFMERGE destkey sourcekey [sourcekey ...]</span><br></pre></td></tr></table></figure></li>
</ul>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/14/Redis%E7%B3%BB%E5%88%97%E7%AC%94%E8%AE%B0%E4%B9%8B%20%E2%80%94%E2%80%94%20%E7%AE%80%E4%BB%8B%E3%80%81%E5%AE%89%E8%A3%85%E3%80%81%E5%85%A5%E9%97%A8%E3%80%81%E9%85%8D%E7%BD%AE/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/14/Redis%E7%B3%BB%E5%88%97%E7%AC%94%E8%AE%B0%E4%B9%8B%20%E2%80%94%E2%80%94%20%E7%AE%80%E4%BB%8B%E3%80%81%E5%AE%89%E8%A3%85%E3%80%81%E5%85%A5%E9%97%A8%E3%80%81%E9%85%8D%E7%BD%AE/" class="post-title-link" itemprop="url">Redis系列笔记之 —— 简介、安装、入门、配置</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-14 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-14T00:00:00+08:00">2021-09-14</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2021-10-04 16:31:37" itemprop="dateModified" datetime="2021-10-04T16:31:37+08:00">2021-10-04</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/Redis/" itemprop="url" rel="index"><span itemprop="name">Redis</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><h2 id="Redis是什么"><a href="#Redis是什么" class="headerlink" title="Redis是什么"></a>Redis是什么</h2><blockquote>
<p>Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库，并提供多种语言的API,是一个由Salvatore Sanfilippo写的key-value存储系统。</p>
</blockquote>
<ul>
<li><strong>Redis</strong> 即 <strong>Remote Dictionary Server</strong> （远程字典服务器），是一个以<strong>字典结构</strong>（<strong>key-value</strong>形式）存储数据的存储系统。</li>
<li>Redis 由 <strong>C语言</strong>编写而成，<strong>开源</strong>，简单稳定，代码量只有几万行，<strong>单线程</strong>模式工作，但性能强劲。</li>
</ul>
<h2 id="特性与优势"><a href="#特性与优势" class="headerlink" title="特性与优势"></a>特性与优势</h2><ul>
<li>Redis的数据都存储在内存中，<strong>读写速度快</strong>（相对于关系型数据库而言）。</li>
<li>Redis支持<strong>数据的持久化</strong>，可以将内存中的数据保存在磁盘中(<strong>异步写入</strong>)，重启的时候可以再次加载进行使用。</li>
<li>Redis 支持<strong>高级数据结构</strong>，如<strong>list，set，zset，hash</strong>（列表、集合、有序集合、散列）等数据结构的存储。</li>
<li>Redis支持<strong>数据的备份</strong>，即master-slave模式的数据备份。</li>
<li>Redis的所有操作都是<strong>原子性</strong>的，意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持<strong>事务</strong>，即原子性，通过MULTI和EXEC指令包起来。</li>
</ul>
<h2 id="功能角色"><a href="#功能角色" class="headerlink" title="功能角色"></a>功能角色</h2><ul>
<li><strong>数据库</strong>,这也是它最开始的用途。</li>
<li><strong>缓存</strong>，Redis可以为每个键设置生存时间（Time To Live）TTL，这一功能可以让Redis扮演缓存系统的功能。</li>
<li><strong>高性能的优先队列</strong>，Redis的列表类型键可以用来实现队列，并且支持阻塞式读取。</li>
</ul>
<h1 id="安装与入门操作"><a href="#安装与入门操作" class="headerlink" title="安装与入门操作"></a>安装与入门操作</h1><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>MacOS中安装Redis很简单，使用包管理工具如HomeBrew即可，</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install redis</span><br></pre></td></tr></table></figure>

<p>在<code>/usr/local/bin</code>下,我们可以看到这么几个可执行文件：</p>
<ul>
<li>redis-server <strong>Redis服务器</strong></li>
<li>redis-cli       <strong>Redis命令行客户端</strong></li>
<li>redis-benchmark	<strong>Redis性能测试工具</strong></li>
<li>redis-check-aof    <strong>AOF文件修复文件</strong></li>
<li>redis-check-rdb	<strong>RDB文件检查文件</strong></li>
<li>redis-sentinel       <strong>Sentinel服务器</strong></li>
</ul>
<p><img src="https://img-blog.csdnimg.cn/20210118202017633.png" alt="在这里插入图片描述"></p>
<p>最常用的是 redis-server 和 redis-cli<br>其中</p>
<ul>
<li>redis-server是Redis的服务器，启动Redis也就是启动redis-server;</li>
<li>redis-cli是Redis<strong>自带的命令行客户端</strong>。</li>
</ul>
<h2 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-server</span><br></pre></td></tr></table></figure>
<p>默认是 6379端口。<br>会出现如下提示：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">51490:C 18 Jan 2021 20:25:26.344 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo</span><br><span class="line">51490:C 18 Jan 2021 20:25:26.345 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=51490, just started</span><br><span class="line">51490:C 18 Jan 2021 20:25:26.345 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.346 * Increased maximum number of open files to 10032 (it was originally set to 256).</span><br><span class="line">                _._                                                  </span><br><span class="line">           _.-``__ &#x27;&#x27;-._                                             </span><br><span class="line">      _.-``    `.  `_.  &#x27;&#x27;-._           Redis 6.0.9 (00000000/0) 64 bit</span><br><span class="line">  .-`` .-```.  ```\/    _.,_ &#x27;&#x27;-._                                   </span><br><span class="line"> (    &#x27;      ,       .-`  | `,    )     Running in standalone mode</span><br><span class="line"> |`-._`-...-` __...-.``-._|&#x27;` _.-&#x27;|     Port: 6379</span><br><span class="line"> |    `-._   `._    /     _.-&#x27;    |     PID: 51490</span><br><span class="line">  `-._    `-._  `-./  _.-&#x27;    _.-&#x27;                                   </span><br><span class="line"> |`-._`-._    `-.__.-&#x27;    _.-&#x27;_.-&#x27;|                                  </span><br><span class="line"> |    `-._`-._        _.-&#x27;_.-&#x27;    |           http://redis.io        </span><br><span class="line">  `-._    `-._`-.__.-&#x27;_.-&#x27;    _.-&#x27;                                   </span><br><span class="line"> |`-._`-._    `-.__.-&#x27;    _.-&#x27;_.-&#x27;|                                  </span><br><span class="line"> |    `-._`-._        _.-&#x27;_.-&#x27;    |                                  </span><br><span class="line">  `-._    `-._`-.__.-&#x27;_.-&#x27;    _.-&#x27;                                   </span><br><span class="line">      `-._    `-.__.-&#x27;    _.-&#x27;                                       </span><br><span class="line">          `-._        _.-&#x27;                                           </span><br><span class="line">              `-.__.-&#x27;                                               </span><br><span class="line"></span><br><span class="line">51490:M 18 Jan 2021 20:25:26.351 # Server initialized</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.353 * Loading RDB produced by version 6.0.9</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.353 * RDB age 623843 seconds</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.353 * RDB memory usage when created 1.02 Mb</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.353 * DB loaded from disk: 0.002 seconds</span><br><span class="line">51490:M 18 Jan 2021 20:25:26.353 * Ready to accept connections</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-server- --port 8888</span><br></pre></td></tr></table></figure>
<p>通过–port自定义端口号。</p>
<h2 id="关闭Redis"><a href="#关闭Redis" class="headerlink" title="关闭Redis"></a>关闭Redis</h2><ol>
<li><p>关闭服务器</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-cli SHUTDOWN</span><br></pre></td></tr></table></figure>
<p>因为Redis此时可能正在将内存中的数据同步到硬盘，所以强行终止Redis进程可能导致数据丢失，所以应该让客户端请求关闭Redis。<br>当Redis收到 <code>SHUTDOWN</code>(小写的也是可以的)之后，</p>
</li>
<li><p>先<strong>断开所有客户端连接</strong>。</p>
</li>
<li><p>根据配置执行<strong>持久化</strong>。</p>
</li>
<li><p>完成<strong>退出</strong>。</p>
</li>
</ol>
<p>在会看到如下提示。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">51578:M 18 Jan 2021 20:32:13.180 # User requested shutdown...</span><br><span class="line">51578:M 18 Jan 2021 20:32:13.180 * Saving the final RDB snapshot before exiting.</span><br><span class="line">51578:M 18 Jan 2021 20:32:13.182 * DB saved on disk</span><br><span class="line">51578:M 18 Jan 2021 20:32:13.182 # Redis is now ready to exit, bye bye...</span><br></pre></td></tr></table></figure>


<ol start="2">
<li>退出客户端<br>使用<code>quit</code>即可</li>
</ol>
<h2 id="客户端的启动"><a href="#客户端的启动" class="headerlink" title="客户端的启动"></a>客户端的启动</h2><p>通过redis-cli向Redis发送命令有两种方式</p>
<ol>
<li><p>将命令作为<code>redis-cli</code>的参数，比如上面的将SHUTDOWN作为参数。</p>
</li>
<li><p>不带参数的启动<code>redis-cli</code>，进入交互模式，自由输入命令，在输入多条命令时方便。</p>
</li>
</ol>
<p>-h、-p自定义地址和端口号。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-cli -h 127.0.0.1 -p 6379</span><br></pre></td></tr></table></figure>

<ul>
<li><strong>在远程服务上执行命令</strong><br>用密码password连接主机名为host，端口号为port的<strong>Redis</strong>服务<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-cli -h host -p port -a password</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="PING检测"><a href="#PING检测" class="headerlink" title="PING检测"></a>PING检测</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; PING</span><br><span class="line">PONG</span><br></pre></td></tr></table></figure>
<p>PING 命令，该命令用于检测 redis 服务是否启动。</p>
<h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>Redis 的配置文件位于 Redis 安装目录下，文件名为 redis.conf。<br><img src="https://img-blog.csdnimg.cn/20210119134549587.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0ODQ2MzI0,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p>
<h2 id="获取配置"><a href="#获取配置" class="headerlink" title="获取配置"></a>获取配置</h2><ul>
<li><strong>获取所有配置</strong><br>在进入redis客户端的交互模式后，输入:<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONFIG GET *</span><br></pre></td></tr></table></figure>
即可获取所有配置。</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">1) &quot;rdbchecksum&quot;</span><br><span class="line">2) &quot;yes&quot;</span><br><span class="line">3) &quot;daemonize&quot;</span><br><span class="line">4) &quot;no&quot;</span><br><span class="line">5) &quot;io-threads-do-reads&quot;</span><br><span class="line">6) &quot;no&quot;</span><br><span class="line">7) &quot;lua-replicate-commands&quot;</span><br><span class="line">8) &quot;yes&quot;</span><br><span class="line">9) &quot;always-show-logo&quot;</span><br><span class="line">10) &quot;no&quot;</span><br><span class="line">11) &quot;protected-mode&quot;</span><br><span class="line">………………</span><br><span class="line">291) &quot;slaveof&quot;</span><br><span class="line">292) &quot;&quot;</span><br><span class="line">293) &quot;notify-keyspace-events&quot;</span><br><span class="line">294) &quot;&quot;</span><br><span class="line">295) &quot;bind&quot;</span><br><span class="line">296) &quot;&quot;</span><br><span class="line">297) &quot;requirepass&quot;</span><br><span class="line">298) &quot;&quot;</span><br><span class="line">299) &quot;oom-score-adj-values&quot;</span><br><span class="line">300) &quot;0 200 800&quot;</span><br></pre></td></tr></table></figure>


<ul>
<li><strong>获取单个配置信息：</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; config get loglevel</span><br><span class="line">1) &quot;loglevel&quot;</span><br><span class="line">2) &quot;notice&quot;</span><br></pre></td></tr></table></figure>
第一行是选项名，第二行是选项值。</li>
</ul>
<h2 id="修改配置"><a href="#修改配置" class="headerlink" title="修改配置"></a>修改配置</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CONFIG SET config_setting_name new_config_value</span><br></pre></td></tr></table></figure>

<p>如：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; config set loglevel warning</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; config get loglevel</span><br><span class="line">1) &quot;loglevel&quot;</span><br><span class="line">2) &quot;warning&quot;</span><br></pre></td></tr></table></figure>


<h2 id="带配置启动"><a href="#带配置启动" class="headerlink" title="带配置启动"></a>带配置启动</h2><p>如果我们要修改的参数过多，可以直接修改配置文件（备份一开始的），然后带着配置文件启动。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-server redis.conf</span><br></pre></td></tr></table></figure>


      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/07/12306/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/09/07/12306/" class="post-title-link" itemprop="url">12306究竟难在哪里</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-09-07 00:00:00" itemprop="dateCreated datePublished" datetime="2021-09-07T00:00:00+08:00">2021-09-07</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2022-03-16 04:13:32" itemprop="dateModified" datetime="2022-03-16T04:13:32+08:00">2022-03-16</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%9E%B6%E6%9E%84/" itemprop="url" rel="index"><span itemprop="name">架构</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="12306究竟难在哪里"><a href="#12306究竟难在哪里" class="headerlink" title="12306究竟难在哪里"></a>12306究竟难在哪里</h1><h2 id="需求分析"><a href="#需求分析" class="headerlink" title="需求分析"></a>需求分析</h2><h3 id="12306-的业务数据量"><a href="#12306-的业务数据量" class="headerlink" title="12306 的业务数据量"></a>12306 的业务数据量</h3><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/31074574">https://zhuanlan.zhihu.com/p/31074574</a></p>
<h3 id="大数据时代"><a href="#大数据时代" class="headerlink" title="大数据时代"></a>大数据时代</h3><p>互联网三高架构：高并发、高性能、高可用，简称三高（3H）<br>互联网应用系统开发肯定经常会看到高并发和高性能这两个词，可谓是耳熟能详。<br>对于12306这样的国民级应用来说，3H能否做到，直接关系到使用者的体验——也就是春运时能否安然买到火车票回家。</p>
<p>像12306这样如此大规模的分布式架构系统，深入研究其架构基础来说对于我们还为时尚早，<br>但是罗马不是一天建成的，此次数据课课设我也不妨从几个技术点，结合当前主流的工具去实践一番，探究其中数据库层面可能遇到的技术瓶颈, 从而窥一斑而见全豹，深化自身对数据库的理解，加强使用的熟练度。</p>
<h3 id="高可用"><a href="#高可用" class="headerlink" title="高可用"></a>高可用</h3><p>集群：一主多从（读写分离的配置）mysql binlog</p>
<p>分布式：数据分片  sharding、mycat</p>
<h4 id="SOA（分布式服务系统）"><a href="#SOA（分布式服务系统）" class="headerlink" title="SOA（分布式服务系统）"></a>SOA（分布式服务系统）</h4><p>面向服务的体系结构（英语：service-oriented architecture）并不特指一种技术，而是一种分布式运算的软件设计方法。软件的部分组件（调用者），可以透过网络上的通用协议调用另一个应用软件组件运行、运作，让调用者获得服务。SOA原则上采用开放标准、与软件资源进行交互并采用表示的标准方式。因此应能跨越厂商、产品与技术。一项服务应视为一个独立的功能单元，可以远程访问并独立运行与更新，例如在线查询信用卡账单。</p>
<p>图</p>
<h3 id="高并发-与-高性能"><a href="#高并发-与-高性能" class="headerlink" title="高并发 与 高性能"></a>高并发 与 高性能</h3><p>高效的IO、高效的计算、流量的负载均衡</p>
<h2 id="高效的IO"><a href="#高效的IO" class="headerlink" title="高效的IO"></a>高效的IO</h2><h3 id="缓存"><a href="#缓存" class="headerlink" title="缓存"></a>缓存</h3><p>读多写少的二八法则在计算机世界里到处都是，下面从三个层面的缓存去深化对缓存的使用。</p>
<h4 id="innodb"><a href="#innodb" class="headerlink" title="innodb"></a>innodb</h4><p>innodb-buffer-pool设置多大<br>Innodb buffer pool缓存池中包含数据的页的数目，包括脏页。单位是page。</p>
<p>innodb_buffer_pool_size 参数为innodb_buffer_pool的大小设置。<br>innodb_buffer_pool_chunk_size参数为InnoDB缓冲池块大小。<br>innodb_buffer_pool_instances参数为缓冲池实例的个数。</p>
<p>规则：<br>innodb_buffer_pool_size &#x3D; innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances *N</p>
<p>系统默认的innodb_buffer_pool_chunk_size为128M<br>innodb_buffer_pool_instances参数的默认设置为1 最大设置为64 ，但是将innodb_buffer_pool_size大小设置为1GB或更大时，此选项才生效。（主要是防止有太多小的instance从而导致性能问题。）</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> @<span class="variable">@innodb</span>_buffer_pool_size<span class="operator">/</span><span class="number">1024</span><span class="operator">/</span><span class="number">1024</span><span class="operator">/</span><span class="number">1024</span>;</span><br><span class="line"><span class="keyword">set</span> <span class="keyword">global</span> innodb_buffer_pool_size <span class="operator">=</span> <span class="number">4227858432</span>;</span><br></pre></td></tr></table></figure>


<p>建议设置为系统内存的50%-80%，但也不是越大越好，要根据具体项目具体分析（操作系统留1G左右，mysql连接数*4M，宿主程序缓存nM）。</p>
<p>查看缓冲池状态</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">show</span> status <span class="keyword">like</span> <span class="string">&#x27;Innodb_buffer_pool_%&#x27;</span></span><br></pre></td></tr></table></figure>
<p>变量解析<br>Innodb_buffer_pool_pages_total参数表示缓存页面的总数量;<br>Innodb_buffer_pool_pages_data代表有数据的缓存页数;<br>Innodb_buffer_pool_pages_free代表没有使用的缓存页数;<br>Innodb_buffer_pool_pages_misc: innodb buffer pool缓存池中当前已经被用作管理用途或hash index而不能用作为普通数据页的数目。</p>
<p>Innodb_buffer_pool_read_requests表示read请求的次数，<br>Innodb_buffer_pool_reads表示从物理磁盘中读取数据的请求次数，</p>
<p>innodb buffer的read命中率 &#x3D;（Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads） &#x2F; Innodb_buffer_pool_read_requests * 100%。<br>如果这个命中率小于95%，建议增大 innodb_buffer_pool_size</p>
<p>如果Innodb_buffer_pool_pages_free偏大的话，证明有很多缓存没有被利用到，这时可以考虑减小缓存;<br>相反Innodb_buffer_pool_pages_data过大就考虑增大缓存。</p>
<p>配置建议规则 （来自 阿里RDS配置参考）</p>
<table>
<thead>
<tr>
<th align="left">实例内存大小（单位：MB）</th>
<th align="left">默认Buffer Pool（单位：MB）</th>
<th align="left">推荐最大Buffer Pool（单位：MB）</th>
</tr>
</thead>
<tbody><tr>
<td align="left">1024</td>
<td align="left">256</td>
<td align="left">256</td>
</tr>
<tr>
<td align="left">2048</td>
<td align="left">512</td>
<td align="left">512</td>
</tr>
<tr>
<td align="left">4096</td>
<td align="left">1536</td>
<td align="left">1536</td>
</tr>
<tr>
<td align="left">8192</td>
<td align="left">4608</td>
<td align="left">4608</td>
</tr>
<tr>
<td align="left">16384</td>
<td align="left">12288</td>
<td align="left">12288</td>
</tr>
<tr>
<td align="left">24576</td>
<td align="left">18432</td>
<td align="left">19456</td>
</tr>
<tr>
<td align="left">32768</td>
<td align="left">24576</td>
<td align="left">25600</td>
</tr>
<tr>
<td align="left">49152</td>
<td align="left">36864</td>
<td align="left">38912</td>
</tr>
<tr>
<td align="left">65536</td>
<td align="left">49152</td>
<td align="left">52224</td>
</tr>
<tr>
<td align="left">98304</td>
<td align="left">73728</td>
<td align="left">77824</td>
</tr>
<tr>
<td align="left">131072</td>
<td align="left">98304</td>
<td align="left">104448</td>
</tr>
<tr>
<td align="left">196608</td>
<td align="left">147456</td>
<td align="left">156672</td>
</tr>
<tr>
<td align="left">229376</td>
<td align="left">172032</td>
<td align="left">183296</td>
</tr>
<tr>
<td align="left">262144</td>
<td align="left">196608</td>
<td align="left">208896</td>
</tr>
<tr>
<td align="left">393216</td>
<td align="left">294912</td>
<td align="left">314368</td>
</tr>
<tr>
<td align="left">491520</td>
<td align="left">368640</td>
<td align="left">393216</td>
</tr>
<tr>
<td align="left">786432</td>
<td align="left">589824</td>
<td align="left">628736</td>
</tr>
</tbody></table>
<h4 id="mybatis-一级缓存、二级缓存"><a href="#mybatis-一级缓存、二级缓存" class="headerlink" title="mybatis 一级缓存、二级缓存"></a>mybatis 一级缓存、二级缓存</h4><h5 id="一级缓存"><a href="#一级缓存" class="headerlink" title="一级缓存"></a>一级缓存</h5><p>查询时：只要两条SQL的下列五个值相同，即可以认为是相同的SQL。<br>Statement Id + Offset + Limmit + Sql + Params</p>
<p>更新时：每次执行update前都会清空localCache,避免脏读</p>
<ol>
<li>MyBatis一级缓存的生命周期和SqlSession一致，级缓存只在数据库会话内部共享。</li>
<li>MyBatis一级缓存内部设计简单，只是一个没有容量限定的HashMap，在缓存的功能性上有所欠缺。</li>
<li>MyBatis的一级缓存最大范围是SqlSession内部，有多个SqlSession或者分布式的环境下，数据库写操作会引起旧数据（不过考虑到mysql的MVCC下的RR，也是有价值的），建议设定缓存级别为Statement。</li>
</ol>
<h5 id="二级缓存"><a href="#二级缓存" class="headerlink" title="二级缓存"></a>二级缓存</h5><p>二级缓存 -&gt; 一级缓存 -&gt; 数据库。</p>
<p>当sqlsession没有调用commit()方法时，二级缓存并没有起到作用。<br>（但是在spring容器管理下的sqlsession 在没有开启事务的时，是不会commit的，二级缓存根本用不上）<br>即使是在 @Transactional 下，又有多少会在事务里调用同一段sql呢？</p>
<ol>
<li>MyBatis的二级缓存相对于一级缓存来说，实现了SqlSession之间缓存数据的共享，同时粒度更加的细，能够到namespace级别，通过Cache接口实现类不同的组合，对Cache的可控性也更强。</li>
<li>MyBatis在多表查询时，极大可能会出现脏数据，有设计上的缺陷，安全使用二级缓存的条件比较苛刻。</li>
<li>在分布式环境下，由于默认的MyBatis Cache实现都是基于本地的，分布式环境下必然会出现读取到脏数据，需要使用集中式缓存将MyBatis的Cache接口实现，有一定的开发成本，直接使用Redis、Memcached等分布式缓存可能成本更低，安全性也更高。</li>
</ol>
<h4 id="redis"><a href="#redis" class="headerlink" title="redis"></a>redis</h4><p>略去<br>更新逻辑</p>
<h2 id="系统架构"><a href="#系统架构" class="headerlink" title="系统架构"></a>系统架构</h2><h3 id="数据分片"><a href="#数据分片" class="headerlink" title="数据分片"></a>数据分片</h3><p>分库分表的需要</p>
<p>垂直分片 </p>
<p>水平分片</p>
<p>分库分表带来的问题：</p>
<ol>
<li>维护困难</li>
<li>sql的支持度</li>
<li>跨库事务</li>
<li>跨库Join<br>后面会结合项目的具体问题进行细讲</li>
</ol>
<h3 id="数据库集群"><a href="#数据库集群" class="headerlink" title="数据库集群"></a>数据库集群</h3><p>数据分片与主从复制</p>
<p>主库会生成一个 log dump 线程,用来给从库 I&#x2F;O 线程传 Binlog 数据。</p>
<p>从库的 I&#x2F;O 线程会去请求主库的 Binlog，并将得到的 Binlog 写到本地的 relay log (中继日志)文件中。</p>
<p>SQL 线程,会读取 relay log 文件中的日志，并解析成 SQL 语句逐一执行。</p>
<h5 id="主节点-log-dump-线程"><a href="#主节点-log-dump-线程" class="headerlink" title="主节点 log dump 线程"></a>主节点 log dump 线程</h5><p>当从节点连接主节点时，主节点会为其创建一个 log dump 线程，用于发送和读取 Binlog 的内容。在读取 Binlog 中的操作时，log dump 线程会对主节点上的 Binlog 加锁；当读取完成发送给从节点之前，锁会被释放。<strong>主节点会为自己的每一个从节点创建一个 log dump 线程</strong>。</p>
<h5 id="从节点I-x2F-O线程"><a href="#从节点I-x2F-O线程" class="headerlink" title="从节点I&#x2F;O线程"></a>从节点I&#x2F;O线程</h5><p>当从节点上执行<code>start slave</code>命令之后，从节点会创建一个 I&#x2F;O 线程用来连接主节点，请求主库中更新的Binlog。I&#x2F;O 线程接收到主节点的 log dump 进程发来的更新之后，保存在本地 relay-log（中继日志）中。</p>
<h5 id="relay-log"><a href="#relay-log" class="headerlink" title="relay log"></a>relay log</h5><p>这里又引申出一个新的日志概念。MySQL 进行主主复制或主从复制的时候会在要复制的服务器下面产生相应的 relay log。</p>
<p>relay log 是怎么产生的呢？</p>
<p>从服务器 I&#x2F;O 线程将主服务器的 Binlog 日志读取过来，解析到各类 Events 之后记录到从服务器本地文件，这个文件就被称为 relay log。然后 SQL 线程会读取 relay log 日志的内容并应用到从服务器，从而使从服务器和主服务器的数据保持一致。中继日志充当缓冲区，这样 master 就不必等待 slave 执行完成才发送下一个事件。</p>
<h2 id="数据库设计"><a href="#数据库设计" class="headerlink" title="数据库设计"></a>数据库设计</h2><h3 id="列车、站点与图论模型"><a href="#列车、站点与图论模型" class="headerlink" title="列车、站点与图论模型"></a>列车、站点与图论模型</h3><p>列车抽象为图论中的路径<br>车站抽象为图论中的点</p>
<p>不过，上述的建模还不够全面，这仅仅是对静态结构的描述，还要加上时间这个维度。</p>
<p>在本次系统实现中，使用Quartz的CronTrigger（基于日历的调度，可精确到秒），进行列车状态变化的驱动。<br>相比于SpringBoot 的  @Scheduled 调度强大的多。</p>
<p>（真实环境下，也许是列车驾驶员人工去发送信息）。</p>
<h3 id="ER图"><a href="#ER图" class="headerlink" title="ER图"></a>ER图</h3><h3 id="业务量究竟大在哪里"><a href="#业务量究竟大在哪里" class="headerlink" title="业务量究竟大在哪里"></a>业务量究竟大在哪里</h3><p>电商最头疼的是什么模块？</p>
<p>订单？支付？都不是，是库存！！！</p>
<p>为什么？因为库存是<strong>多读多写</strong>的场景，是整个性能的瓶颈！</p>
<p>订单，就用户一个人可以写，你爱怎么改怎么改，分布式也好做，因为只有单写。</p>
<p>库存不一样，同一个sku每个订单都要改库存，这太恐怖了，一般电商还可以通过分仓库，预分配等手段解决，火车票你怎么搞！！分仓库？哦，今天北京发往上海的G123车钱，华北地区还有三张票，西南地区库存为0？不可能！！！全国人民在极短的时间内，大量订单抢同一个库存，这本来就已经非常困难了，再加上，几乎所有热门车票都特么这么抢！而且，一列火车，由于乘客的起始站和终点站不同，可以逻辑上分成多种商品，但这些商品又相互有库存关联，无法划为独立sku…想想就头疼，再加上在多写的库上做分布式，同步问题又是老大难。所以，12306非常困难！！</p>
<h3 id="库存是什么-——-火车售票的余票算法"><a href="#库存是什么-——-火车售票的余票算法" class="headerlink" title="库存是什么? —— 火车售票的余票算法"></a>库存是什么? —— 火车售票的余票算法</h3><h4 id="路径节点对构成-sku"><a href="#路径节点对构成-sku" class="headerlink" title="路径节点对构成 sku"></a>路径节点对构成 sku</h4><p>网上自称某宝工程师写的12306文章。他们将<strong>路径上的每个站点对</strong>独立成一件商品，每次购、退票都需要查询删改库存，造成巨大的数据库操作开销。</p>
<p>将每站点全部商品位化，是为了<strong>营造高并发的假象</strong>而已，白白浪费了计算资源。以每趟车2000张票为例子。</p>
<p>某宝的工程师算法逻辑是直接操作库的逻辑，那么将数据库映射成为bmp处理，但这又带来新的问题，比如锁定机制，数据同步机制，写入仲裁机制，这些在本算法中由天然的cpu硬件机制来实施。与硬件有一致性，机制成熟算法健壮性有保证。如果人为的另立机制想拓展bmp算法的性能会导致很多问题，</p>
<p>![image-20220316031959849](..&#x2F;..&#x2F;..&#x2F;..&#x2F;..&#x2F;Library&#x2F;Application Support&#x2F;typora-user-images&#x2F;image-20220316031959849.png)</p>
<h4 id="站点座位bitmap法"><a href="#站点座位bitmap法" class="headerlink" title="站点座位bitmap法"></a>站点座位bitmap法</h4><p>抢票的基本单位是某一列列车。</p>
<p>对<strong>此列列车经过的所有站点都创建等容量大小的位图（容量大小为座位数量）</strong>—— 当然，如果有多个类型的座位，同理每种类型都创建位图即可。</p>
<p><strong>位图0表示空闲，1表示已占。</strong></p>
<p><strong>用户每次买票获取此列车对应所有中途站点的位图，对这些位图（或者说二进制串）做按位或运算</strong>，</p>
<p>运算结果为1的表明不能被购买（只要有一个为1，就不能购买），为0的表明还没有人购买，可以售出。</p>
<p>如果有用户抢到某个余座，需要将这几个连续的位图的对应bit的0全部改成1（原子地更新）。</p>
<p><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s?__biz=MzkxNDEyOTI0OQ==&mid=2247484331&idx=1&sn=3e0294efe74cd7b9a421aef778081c69&source=41#wechat_redirect">https://mp.weixin.qq.com/s?__biz=MzkxNDEyOTI0OQ==&amp;mid=2247484331&amp;idx=1&amp;sn=3e0294efe74cd7b9a421aef778081c69&amp;source=41#wechat_redirect</a></p>
<h2 id="”库存“扣减的问题"><a href="#”库存“扣减的问题" class="headerlink" title="”库存“扣减的问题"></a>”库存“扣减的问题</h2><h3 id="超卖问题的解决"><a href="#超卖问题的解决" class="headerlink" title="超卖问题的解决"></a>超卖问题的解决</h3><h4 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a>悲观锁</h4><p>悲观锁（Pessimistic Lock），顾名思义，就是很悲观，每次去拿数据的时候都认为别人会修改，所以每次在拿数据的时候都会上锁，这样别人想拿这个数据就会block直到它拿到锁。</p>
<p>悲观锁：假定会发生并发冲突，屏蔽一切可能违反数据完整性的操作。</p>
<p>Java synchronized、ReentrantLock 就属于悲观锁的一种实现，每次线程要修改数据时都先获得锁，保证同一时刻只有一个线程能操作数据，其他线程则会被block。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> ... LOCK <span class="keyword">IN</span> SHARE MODE;  <span class="operator">/</span><span class="operator">/</span> <span class="keyword">SELECT</span> ... <span class="keyword">FOR</span> SHARE;</span><br><span class="line"><span class="keyword">SELECT</span> ... <span class="keyword">FOR</span> <span class="keyword">UPDATE</span>;</span><br></pre></td></tr></table></figure>



<p>具体一点的一点：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">&quot;selectWithXLock&quot;</span> <span class="attr">resultMap</span>=<span class="string">&quot;TrainStationSeatStatusMap&quot;</span>&gt;</span></span><br><span class="line">    select</span><br><span class="line">    train_id,</span><br><span class="line">    working_date,</span><br><span class="line">    type,</span><br><span class="line">    station_id,</span><br><span class="line">    status</span><br><span class="line">    from train_station_seat_status</span><br><span class="line">    where</span><br><span class="line">    train_id = #&#123;trainId&#125;             // 列车id</span><br><span class="line">    and working_date = #&#123;workingDate&#125; // 日期</span><br><span class="line">    and type = #&#123;type&#125;                // 座位类型</span><br><span class="line">    and station_id in                 // 车站id</span><br><span class="line">    <span class="tag">&lt;<span class="name">foreach</span> <span class="attr">item</span>=<span class="string">&quot;item&quot;</span> <span class="attr">index</span>=<span class="string">&quot;index&quot;</span> <span class="attr">collection</span>=<span class="string">&quot;stationIds&quot;</span></span></span><br><span class="line"><span class="tag">             <span class="attr">open</span>=<span class="string">&quot;(&quot;</span> <span class="attr">separator</span>=<span class="string">&quot;,&quot;</span> <span class="attr">close</span>=<span class="string">&quot;)&quot;</span>&gt;</span></span><br><span class="line">        #&#123;item&#125;</span><br><span class="line">    <span class="tag">&lt;/<span class="name">foreach</span>&gt;</span></span><br><span class="line">    for update ;                      // 写锁</span><br><span class="line"><span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p><strong>悲观锁</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 悲观锁</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> SeatLocation <span class="title function_">buyTicketAndOccupySeatWithPessimisticLock</span><span class="params">(DrivingPlan drivingPlan, SeatType seatType)</span> <span class="keyword">throws</span> TicketSaleCoreException &#123;</span><br><span class="line">    <span class="type">Integer</span> <span class="variable">trainId</span> <span class="operator">=</span> drivingPlan.getTrain().getTrainId();</span><br><span class="line">    <span class="type">LocalDate</span> <span class="variable">workingDate</span> <span class="operator">=</span> drivingPlan.getWorkingDate();</span><br><span class="line">    ArrayList&lt;Integer&gt; stationIds = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    drivingPlan.getSeatStatusOfPassStations(seatType).forEach(trainStationSeatStatus -&gt; stationIds.add(trainStationSeatStatus.getStationId()));</span><br><span class="line">    <span class="comment">// 加互斥锁，一次性拿到所有需要的状态位图</span></span><br><span class="line">    List&lt;TrainStationSeatStatus&gt; trainStationSeatStatuses = trainStationSeatStatusMapper.selectWithXLock(trainId, workingDate, seatType, stationIds);</span><br><span class="line">    <span class="comment">// 检查位图结构</span></span><br><span class="line">    checkHasSameCapacity(trainStationSeatStatuses);</span><br><span class="line">    <span class="comment">// 二进制串集作按位或运算</span></span><br><span class="line">    <span class="type">boolean</span>[] availSeats = getAvailSeats(trainStationSeatStatuses);</span><br><span class="line">    <span class="comment">// 获取所有可用的座位</span></span><br><span class="line">    List&lt;Integer&gt; availSeatsIds = getAvailSeats(availSeats);</span><br><span class="line">    <span class="keyword">if</span> (availSeatsIds.isEmpty()) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 随机从空闲座位中挑一个空闲座位</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">idx</span> <span class="operator">=</span> randomSeatIndex(availSeats);</span><br><span class="line">    <span class="comment">// 更改位图</span></span><br><span class="line">    occupyOneSeat(idx, trainStationSeatStatuses);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 更改座位-位图状态</span></span><br><span class="line">    trainStationSeatStatuses.forEach(trainStationSeatStatus -&gt; &#123;</span><br><span class="line">        <span class="type">Integer</span> <span class="variable">stationId</span> <span class="operator">=</span> trainStationSeatStatus.getStationId();</span><br><span class="line">        trainStationSeatStatusMapper.update(</span><br><span class="line">                trainStationSeatStatus,</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">UpdateWrapper</span>&lt;TrainStationSeatStatus&gt;()</span><br><span class="line">                        .eq(<span class="string">&quot;train_id&quot;</span>, trainId)</span><br><span class="line">                        .eq(<span class="string">&quot;working_date&quot;</span>, workingDate)</span><br><span class="line">                        .eq(<span class="string">&quot;type&quot;</span>, seatType)</span><br><span class="line">                        .eq(<span class="string">&quot;station_id&quot;</span>, stationId)</span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 查询对应位置的座位</span></span><br><span class="line">    <span class="keyword">return</span> seatMapper.selectOne(<span class="keyword">new</span> <span class="title class_">QueryWrapper</span>&lt;TrainPatternSeatMap&gt;()</span><br><span class="line">            .eq(<span class="string">&quot;train_pattern_id&quot;</span>, drivingPlan.getTrain().getTrainPatternId())</span><br><span class="line">            .eq(<span class="string">&quot;type&quot;</span>, seatType)</span><br><span class="line">            .eq(<span class="string">&quot;idx&quot;</span>, idx)).getSeatLocation();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h4><p>乐观锁（Optimistic Lock），顾名思义，就是很乐观，每次去拿数据的时候都认为别人不会修改，所以不会上锁，但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景，这样可以提高吞吐量。</p>
<p>乐观锁：假设不会发生并发冲突，只在提交操作时检查是否违反数据完整性。</p>
<p>使用数据版本（Version）记录机制实现，这是乐观锁最常用的一种实现方式。何谓数据版本？即为数据增加一个版本标识，一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时，将version字段的值一同读出，数据每更新一次，对此version值加一。当我们提交更新的时候，判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对，如果数据库表当前版本号与第一次取出来的version值相等，则予以更新，否则认为是过期数据。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">UPDATE</span> ... <span class="keyword">SET</span> ... <span class="operator">=</span> ... <span class="keyword">WHERE</span> version <span class="operator">=</span> #&#123;version&#125;</span><br></pre></td></tr></table></figure>



<p>但是在本例中，不能简单地使用这个方案，因为这里需要原子性地一次性修改掉多个位串记录。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 乐观锁</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> SeatLocation <span class="title function_">buyTicketAndOccupySeatWithOptimisticLock</span><span class="params">(DrivingPlan drivingPlan, SeatType seatType)</span> <span class="keyword">throws</span> TicketSaleCoreException, OptimisticLockFailure &#123;</span><br><span class="line">        <span class="type">Integer</span> <span class="variable">trainId</span> <span class="operator">=</span> drivingPlan.getTrain().getTrainId();</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">workingDate</span> <span class="operator">=</span> drivingPlan.getWorkingDate();</span><br><span class="line"><span class="comment">//         先乐观锁尝试</span></span><br><span class="line"><span class="comment">//         无锁读</span></span><br><span class="line">        List&lt;TrainStationSeatStatus&gt; seatStatusOfPassStations = drivingPlan.getSeatStatusOfPassStations(seatType);</span><br><span class="line">        List&lt;TrainStationSeatStatus&gt; realStationSeatStatuses = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">        seatStatusOfPassStations.forEach(trainStationSeatStatus -&gt; &#123;</span><br><span class="line">            <span class="type">TrainStationSeatStatus</span> <span class="variable">status</span> <span class="operator">=</span> trainStationSeatStatusMapper.selectOne(<span class="keyword">new</span> <span class="title class_">QueryWrapper</span>&lt;TrainStationSeatStatus&gt;()</span><br><span class="line">                    .eq(<span class="string">&quot;train_id&quot;</span>, trainId)</span><br><span class="line">                    .eq(<span class="string">&quot;working_date&quot;</span>, workingDate)</span><br><span class="line">                    .eq(<span class="string">&quot;type&quot;</span>, seatType)</span><br><span class="line">                    .eq(<span class="string">&quot;station_id&quot;</span>, trainStationSeatStatus.getStationId()));</span><br><span class="line">            realStationSeatStatuses.add(status);</span><br><span class="line">        &#125;);</span><br><span class="line">        seatStatusOfPassStations = realStationSeatStatuses;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 根据二进制位图检查座位的可用情况</span></span><br><span class="line">        checkHasSameCapacity(seatStatusOfPassStations);</span><br><span class="line">        <span class="type">boolean</span>[] availSeats = getAvailSeats(seatStatusOfPassStations);</span><br><span class="line">        List&lt;Integer&gt; availSeatsIds = getAvailSeats(availSeats);</span><br><span class="line">        <span class="comment">// 快照读，若此时无票，则直接返回</span></span><br><span class="line">        <span class="keyword">if</span> (availSeatsIds.isEmpty()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 尝试占座</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">idx</span> <span class="operator">=</span> randomSeatIndex(availSeats);</span><br><span class="line">        occupyOneSeat(idx, seatStatusOfPassStations);</span><br><span class="line">        <span class="keyword">for</span> (TrainStationSeatStatus trainStationSeatStatus : seatStatusOfPassStations) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">succ</span> <span class="operator">=</span> trainStationSeatStatusMapper.update(trainStationSeatStatus,</span><br><span class="line">                    <span class="keyword">new</span> <span class="title class_">UpdateWrapper</span>&lt;TrainStationSeatStatus&gt;()</span><br><span class="line">                            .eq(<span class="string">&quot;train_id&quot;</span>, trainId)</span><br><span class="line">                            .eq(<span class="string">&quot;working_date&quot;</span>, workingDate)</span><br><span class="line">                            .eq(<span class="string">&quot;type&quot;</span>, trainStationSeatStatus.getType())</span><br><span class="line">                            .eq(<span class="string">&quot;station_id&quot;</span>, trainStationSeatStatus.getStationId()));</span><br><span class="line">            <span class="comment">// 只要有一个更新失败，前面的操作必须全部回滚，这里的回滚绝不可以是自己做&quot;补偿操作&quot;，而应该是抛出异常迫使回滚</span></span><br><span class="line">            <span class="keyword">if</span> (succ == <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">OptimisticLockFailure</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 流程到这里，表明乐观锁争抢修改成功</span></span><br><span class="line">        <span class="comment">// 查询对应位置的座位</span></span><br><span class="line">        <span class="keyword">return</span> seatMapper.selectOne(<span class="keyword">new</span> <span class="title class_">QueryWrapper</span>&lt;TrainPatternSeatMap&gt;()</span><br><span class="line">                .eq(<span class="string">&quot;train_pattern_id&quot;</span>, drivingPlan.getTrain().getTrainPatternId())</span><br><span class="line">                .eq(<span class="string">&quot;type&quot;</span>, seatType)</span><br><span class="line">                .eq(<span class="string">&quot;idx&quot;</span>, idx)).getSeatLocation();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>







<h4 id="自适应锁"><a href="#自适应锁" class="headerlink" title="自适应锁"></a>自适应锁</h4><p>不要有一种错觉，觉得乐观锁实现了无锁并发安全，就觉得乐观锁的性能远远优越悲观锁，</p>
<p>这个是有几个前提的，读多写少，竞争程度不激烈，短事务。（总而言之，减少因为乐观锁加锁失败重试的次数）</p>
<p>所以，我的策略是，对于上述两种加锁方式，同时予以实现。<br>具体的，默认先使用乐观锁并发修改数据，同时设定乐观锁失败重试次数做多为1次（可以根据实际情况修改配置），如果仍然未修改成功，再改用悲观锁进行竞争修改数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> SeatLocation <span class="title function_">buyTicketAndOccupySeat</span><span class="params">(DrivingPlan drivingPlan, SeatType seatType)</span> <span class="keyword">throws</span> TicketSaleCoreException &#123;</span><br><span class="line"><span class="comment">//        System.out.println(&quot;乐观锁最大重试次数 &quot; + MAX_OPTIMISTIC_LOCK_RETRIES);</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; MAX_OPTIMISTIC_LOCK_RETRIES; i++) &#123;</span><br><span class="line">            <span class="type">SeatLocation</span> <span class="variable">seatLocation</span> <span class="operator">=</span> transactionTemplate.execute(transactionStatus -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="comment">// 没有抛出自定义的异常，说明一切正常，</span></span><br><span class="line">                    <span class="keyword">return</span> buyTicketAndOccupySeatWithOptimisticLock(drivingPlan, seatType);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (OptimisticLockFailure | TicketSaleCoreException failure) &#123;</span><br><span class="line">                    transactionStatus.setRollbackOnly();</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="comment">// 乐观锁已经争抢成功</span></span><br><span class="line">            <span class="keyword">if</span> (seatLocation != <span class="literal">null</span>) <span class="keyword">return</span> seatLocation;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> buyTicketAndOccupySeatWithPessimisticLock(drivingPlan, seatType);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>



<h2 id="技术难点举例"><a href="#技术难点举例" class="headerlink" title="技术难点举例"></a>技术难点举例</h2><h3 id="库存超卖"><a href="#库存超卖" class="headerlink" title="库存超卖"></a>库存超卖</h3><p>这里的库存指的就是一般意义上的库存：</p>
<blockquote>
<p>常见的库存扣减方式有：</p>
<ul>
<li>下单减库存：即当买家下单后，在商品的总库存中减去买家购买数量。下单减库存是最简单的减库存方式，也是控制最精确的一种，下单时直接通过数据库的事务机制控制商品库存，这样一定不会出现超卖的情况。但是你要知道，有些人下完单可能并不会付款。</li>
<li>付款减库存：即买家下单后，并不立即减库存，而是等到有用户付款后才真正减库存，否则库存一直保留给其他买家。但因为付款时才减库存，如果并发比较高，有可能出现买家下单后付不了款的情况，因为可能商品已经被其他人买走了。</li>
<li>预扣库存：这种方式相对复杂一些，买家下单后，库存为其保留一定的时间（如 30 分钟），超过这个时间，库存将会自动释放，释放后其他买家就可以继续购买。在买家付款前，系统会校验该订单的库存是否还有保留：如果没有保留，则再次尝试预扣；如果库存不足（也就是预扣失败）则不允许继续付款；如果预扣成功，则完成付款并实际地减去库存。<br> 至于采用哪一种减库存方式更多是业务层面的考虑，减库存最核心的是大并发请求时保证数据库中的库存字段值不能为负数。</li>
</ul>
</blockquote>
<p>解决方案已经在上面已经有了部分描述——介绍了纯数据库层面的解决方案。</p>
<p>下面介绍一下使用Redis的做法：<strong>Lua脚本处理秒杀请求</strong></p>
<p>大致处理过程如下：</p>
<ol>
<li>将商品信息预热到redis中；</li>
<li>用户扣库存请求用lua在redis里完成</li>
<li>及时将redis的记录落到数据库（定时任务）</li>
</ol>
<h3 id="避免重复下单"><a href="#避免重复下单" class="headerlink" title="避免重复下单"></a>避免重复下单</h3><p>用户快速点了两次 “提交订单”  按钮，浏览器会向后端发送两条创建订单的请求，最终会创建两条一模一样的订单。</p>
<p><strong>幂等性如何保证</strong>？</p>
<ol>
<li><strong>先select后insert</strong></li>
</ol>
<p>这种插入数据（不论是新增一行，还是将修改字段的空值）的场景比较容易处理，先查后改。</p>
<ol start="2">
<li><strong>数据库自身特性 “主键唯一约束”</strong></li>
</ol>
<p>利用数据库自身特性 “主键唯一约束”，在插入订单记录时，带上主键值，如果订单重复，记录插入会失败。</p>
<p>操作过程：</p>
<p>引入一个服务，用于生成一个“全局唯一的订单号”；</p>
<p>进入创建订单页面时，前端请求该服务，预生成订单ID；</p>
<p>提交订单时，请求参数除了业务参数外，还要带上这个预生成订单ID。</p>
<ol start="3">
<li><strong>建防重表</strong></li>
</ol>
<p>有时候表中并非所有的场景都不允许产生重复的数据，只有某些特定场景才不允许。这时候，直接在表中加唯一索引，显然是不太合适的。</p>
<p>针对这种情况，我们可以通过<code>建防重表</code>来解决问题。</p>
<p>该表可以只包含两个字段：<code>id</code> 和 <code>唯一索引</code>，唯一索引可以是多个字段比如：name、code等组合起来的唯一标识，例如：susan_0001。</p>
<ol start="4">
<li><strong>建立业务状态机</strong></li>
</ol>
<p>很多时候业务表是有状态的，比如订单表中有：1-下单、2-已支付、3-完成、4-撤销等状态。如果这些状态的值是有规律的，按照业务节点正好是从小到大，我们就能通过它来保证接口的幂等性。</p>
<ol start="5">
<li><strong>分布式锁</strong></li>
</ol>
<p>具体使用分布式锁，各式各样了。不过核心思想就是<code>setnx</code>。</p>
<ol start="6">
<li><strong>带过期期限的token</strong></li>
</ol>
<p>请求时先请求token，token存redis，带过期时间。实际业务处理时redis里有token直接返回，反之执行数据操作。</p>
<h3 id="订单分库分表，多维度查询"><a href="#订单分库分表，多维度查询" class="headerlink" title="订单分库分表，多维度查询"></a>订单分库分表，多维度查询</h3><p>如果电商网站的订单数过多，我们一般会想到 <code>分库分表</code> 解决策略。没问题，这个大方向是对的。</p>
<p><strong>但是查询维度很多。</strong></p>
<p>1、买家，查询 <code>我的订单</code> 列表，需要根据 <code>buyer_id</code> 来查询</p>
<p>2、查看订单详情，需要根据 <code>order_id</code> 来查询</p>
<p>3、卖家，查询 <code>我的销售</code> 列表，需要根据 <code>seller_id</code> 来查询</p>
<p><strong>而订单分表只有一个分表键，如何满足多维度 SQL 操作呢</strong>？</p>
<p>如何调节分片键与索引的矛盾: <strong>冗余</strong>。</p>
<ol>
<li>全量冗余</li>
<li>关系冗余</li>
</ol>
<p>举例:<br>order表</p>
<p>![order_table](..&#x2F;..&#x2F;..&#x2F;..&#x2F;..&#x2F;Library&#x2F;Application Support&#x2F;typora-user-images&#x2F;image-20220316031324461.png)</p>
<h3 id="分布式事务"><a href="#分布式事务" class="headerlink" title="分布式事务"></a>分布式事务</h3><h4 id="XA"><a href="#XA" class="headerlink" title="XA"></a>XA</h4><h4 id="Seata-的-AT"><a href="#Seata-的-AT" class="headerlink" title="Seata 的 AT"></a>Seata 的 AT</h4>
      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/08/23/HikariCP%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="SongyangJi">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="JsyBlog">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | JsyBlog">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2021/08/23/HikariCP%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF/" class="post-title-link" itemprop="url">HikariCP配置信息</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>
      

      <time title="创建时间：2021-08-23 00:00:00 / 修改时间：13:09:22" itemprop="dateCreated datePublished" datetime="2021-08-23T00:00:00+08:00">2021-08-23</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <table>
<thead>
<tr>
<th><strong>name</strong></th>
<th><strong>描述</strong></th>
<th><strong>构造器默认值</strong></th>
<th><strong>默认配置validate之后的值</strong></th>
<th><strong>validate重置</strong></th>
</tr>
</thead>
<tbody><tr>
<td>autoCommit</td>
<td>自动提交从池中返回的连接</td>
<td>TRUE</td>
<td>TRUE</td>
<td>–</td>
</tr>
<tr>
<td>connectionTimeout</td>
<td>等待来自池的连接的最大毫秒数</td>
<td>SECONDS.toMillis(30) &#x3D; 30000</td>
<td>30000</td>
<td>如果小于250毫秒，则被重置回30秒</td>
</tr>
<tr>
<td>idleTimeout</td>
<td>连接允许在池中闲置的最长时间</td>
<td>MINUTES.toMillis(10) &#x3D; 600000</td>
<td>600000</td>
<td>如果idleTimeout+1秒&gt;maxLifetime 且 maxLifetime&gt;0，则会被重置为0（代表永远不会退出）；如果idleTimeout!&#x3D;0且小于10秒，则会被重置为10秒</td>
</tr>
<tr>
<td>maxLifetime</td>
<td>池中连接最长生命周期</td>
<td>MINUTES.toMillis(30) &#x3D; 1800000</td>
<td>1800000</td>
<td>如果不等于0且小于30秒则会被重置回30分钟</td>
</tr>
<tr>
<td>connectionTestQuery</td>
<td>如果您的驱动程序支持JDBC4，我们强烈建议您不要设置此属性</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>minimumIdle</td>
<td>池中维护的最小空闲连接数</td>
<td>-1</td>
<td>10</td>
<td>minIdle&lt;0或者minIdle&gt;maxPoolSize,则被重置为maxPoolSize</td>
</tr>
<tr>
<td>maximumPoolSize</td>
<td>池中最大连接数，包括闲置和使用中的连接</td>
<td>-1</td>
<td>10</td>
<td>如果maxPoolSize小于1，则会被重置。当minIdle&lt;&#x3D;0被重置为DEFAULT_POOL_SIZE则为10;如果minIdle&gt;0则重置为minIdle的值</td>
</tr>
<tr>
<td>metricRegistry</td>
<td>该属性允许您指定一个 Codahale &#x2F; Dropwizard MetricRegistry 的实例，供池使用以记录各种指标</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>healthCheckRegistry</td>
<td>该属性允许您指定池使用的Codahale &#x2F; Dropwizard HealthCheckRegistry的实例来报告当前健康信息</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>poolName</td>
<td>连接池的用户定义名称，主要出现在日志记录和JMX管理控制台中以识别池和池配置</td>
<td>null</td>
<td>HikariPool-1</td>
<td>–</td>
</tr>
<tr>
<td>initializationFailTimeout</td>
<td>如果池无法成功初始化连接，则此属性控制池是否将 fail fast</td>
<td>1</td>
<td>1</td>
<td>–</td>
</tr>
<tr>
<td>isolateInternalQueries</td>
<td>是否在其自己的事务中隔离内部池查询，例如连接活动测试</td>
<td>FALSE</td>
<td>FALSE</td>
<td>–</td>
</tr>
<tr>
<td>allowPoolSuspension</td>
<td>控制池是否可以通过JMX暂停和恢复</td>
<td>FALSE</td>
<td>FALSE</td>
<td>–</td>
</tr>
<tr>
<td>readOnly</td>
<td>从池中获取的连接是否默认处于只读模式</td>
<td>FALSE</td>
<td>FALSE</td>
<td>–</td>
</tr>
<tr>
<td>registerMbeans</td>
<td>是否注册JMX管理Bean（MBeans）</td>
<td>FALSE</td>
<td>FALSE</td>
<td>–</td>
</tr>
<tr>
<td>catalog</td>
<td>为支持 catalog 概念的数据库设置默认 catalog</td>
<td>driver default</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>connectionInitSql</td>
<td>该属性设置一个SQL语句，在将每个新连接创建后，将其添加到池中之前执行该语句。</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>driverClassName</td>
<td>HikariCP将尝试通过仅基于jdbcUrl的DriverManager解析驱动程序，但对于一些较旧的驱动程序，还必须指定driverClassName</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>transactionIsolation</td>
<td>控制从池返回的连接的默认事务隔离级别</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>validationTimeout</td>
<td>连接将被测试活动的最大时间量</td>
<td>SECONDS.toMillis(5) &#x3D; 5000</td>
<td>5000</td>
<td>如果小于250毫秒，则会被重置回5秒</td>
</tr>
<tr>
<td>leakDetectionThreshold</td>
<td>记录消息之前连接可能离开池的时间量，表示可能的连接泄漏</td>
<td>0</td>
<td>0</td>
<td>如果大于0且不是单元测试，则进一步判断：(leakDetectionThreshold &lt; SECONDS.toMillis(2) or (leakDetectionThreshold &gt; maxLifetime &amp;&amp; maxLifetime &gt; 0)，会被重置为0 . 即如果要生效则必须&gt;0，而且不能小于2秒，而且当maxLifetime &gt; 0时不能大于maxLifetime</td>
</tr>
<tr>
<td>dataSource</td>
<td>这个属性允许你直接设置数据源的实例被池包装，而不是让HikariCP通过反射来构造它</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>schema</td>
<td>该属性为支持模式概念的数据库设置默认模式</td>
<td>driver default</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>threadFactory</td>
<td>此属性允许您设置将用于创建池使用的所有线程的java.util.concurrent.ThreadFactory的实例。</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
<tr>
<td>scheduledExecutor</td>
<td>此属性允许您设置将用于各种内部计划任务的java.util.concurrent.ScheduledExecutorService实例</td>
<td>null</td>
<td>null</td>
<td>–</td>
</tr>
</tbody></table>
<blockquote>
<p> <a target="_blank" rel="noopener" href="https://github.com/brettwooldridge/HikariCP">HikariCP on github</a></p>
</blockquote>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




  <nav class="pagination">
    <a class="extend prev" rel="prev" title="上一页" aria-label="上一页" href="/page/22/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/22/">22</a><span class="page-number current">23</span><a class="page-number" href="/page/24/">24</a><span class="space">&hellip;</span><a class="page-number" href="/page/26/">26</a><a class="extend next" rel="next" title="下一页" aria-label="下一页" href="/page/24/"><i class="fa fa-angle-right"></i></a>
  </nav>

</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">SongyangJi</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>





  





</body>
</html>
